X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/1df5f87f1309a8daa30dabdee855f48ae40d14ab..6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174:/qt/api/qscriptvalue_p.h?ds=inline diff --git a/qt/api/qscriptvalue_p.h b/qt/api/qscriptvalue_p.h deleted file mode 100644 index f98a06a..0000000 --- a/qt/api/qscriptvalue_p.h +++ /dev/null @@ -1,1220 +0,0 @@ -/* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef qscriptvalue_p_h -#define qscriptvalue_p_h - -#include "qscriptconverter_p.h" -#include "qscriptengine_p.h" -#include "qscriptvalue.h" -#include -#include -#include -#include -#include -#include -#include -#include - -class QScriptEngine; -class QScriptValue; - -/* - \internal - \class QScriptValuePrivate - - Implementation of QScriptValue. - The implementation is based on a state machine. The states names are included in - QScriptValuePrivate::State. Each method should check for the current state and then perform a - correct action. - - State: - Invalid -> QSVP is invalid, no assumptions should be made about class members (apart from m_value). - CString -> QSVP is created from QString or const char* and no JSC engine has been associated yet. - Current value is kept in m_string, - CNumber -> QSVP is created from int, uint, double... and no JSC engine has been bind yet. Current - value is kept in m_number - CBool -> QSVP is created from bool and no JSC engine has been associated yet. Current value is kept - in m_bool - CNull -> QSVP is null, but a JSC engine hasn't been associated yet. - CUndefined -> QSVP is undefined, but a JSC engine hasn't been associated yet. - JSValue -> QSVP is associated with engine, but there is no information about real type, the state - have really short live cycle. Normally it is created as a function call result. - JSPrimitive -> QSVP is associated with engine, and it is sure that it isn't a JavaScript object. - JSObject -> QSVP is associated with engine, and it is sure that it is a JavaScript object. - - Each state keep all necessary information to invoke all methods, if not it should be changed to - a proper state. Changed state shouldn't be reverted. - - The QScriptValuePrivate use the JSC C API directly. The QSVP type is equal to combination of - the JSValueRef and the JSObjectRef, and it could be automatically casted to these types by cast - operators. -*/ - -class QScriptValuePrivate : public QSharedData { -public: - inline static QScriptValuePrivate* get(const QScriptValue& q); - inline static QScriptValue get(const QScriptValuePrivate* d); - inline static QScriptValue get(QScriptValuePrivate* d); - - inline ~QScriptValuePrivate(); - - inline QScriptValuePrivate(); - inline QScriptValuePrivate(const QString& string); - inline QScriptValuePrivate(bool value); - inline QScriptValuePrivate(int number); - inline QScriptValuePrivate(uint number); - inline QScriptValuePrivate(qsreal number); - inline QScriptValuePrivate(QScriptValue::SpecialValue value); - - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, int value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value); - - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value); - inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object); - - inline bool isValid() const; - inline bool isBool(); - inline bool isNumber(); - inline bool isNull(); - inline bool isString(); - inline bool isUndefined(); - inline bool isError(); - inline bool isObject(); - inline bool isFunction(); - inline bool isArray(); - inline bool isDate(); - - inline QString toString() const; - inline qsreal toNumber() const; - inline bool toBool() const; - inline qsreal toInteger() const; - inline qint32 toInt32() const; - inline quint32 toUInt32() const; - inline quint16 toUInt16() const; - - inline QScriptValuePrivate* toObject(QScriptEnginePrivate* engine); - inline QScriptValuePrivate* toObject(); - inline QDateTime toDateTime(); - inline QScriptValuePrivate* prototype(); - inline void setPrototype(QScriptValuePrivate* prototype); - - inline bool equals(QScriptValuePrivate* other); - inline bool strictlyEquals(QScriptValuePrivate* other); - inline bool instanceOf(QScriptValuePrivate* other); - inline bool assignEngine(QScriptEnginePrivate* engine); - - inline QScriptValuePrivate* property(const QString& name, const QScriptValue::ResolveFlags& mode); - inline QScriptValuePrivate* property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode); - inline QScriptValuePrivate* property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode); - inline JSValueRef property(quint32 property, JSValueRef* exception); - inline JSValueRef property(JSStringRef property, JSValueRef* exception); - inline bool hasOwnProperty(quint32 property); - inline bool hasOwnProperty(JSStringRef property); - template - inline QScriptValuePrivate* property(T name, const QScriptValue::ResolveFlags& mode); - - inline void setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); - inline void setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); - inline void setProperty(const quint32 indexArray, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); - inline void setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception); - inline void setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception); - inline void deleteProperty(quint32 property, JSValueRef* exception); - inline void deleteProperty(JSStringRef property, JSValueRef* exception); - template - inline void setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); - - QScriptValue::PropertyFlags propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode); - QScriptValue::PropertyFlags propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode); - QScriptValue::PropertyFlags propertyFlags(const JSStringRef name, const QScriptValue::ResolveFlags& mode); - - inline QScriptValuePrivate* call(const QScriptValuePrivate* , const QScriptValueList& args); - - inline operator JSValueRef() const; - inline operator JSObjectRef() const; - - inline QScriptEnginePrivate* engine() const; - -private: - // Please, update class documentation when you change the enum. - enum State { - Invalid = 0, - CString = 0x1000, - CNumber, - CBool, - CNull, - CUndefined, - JSValue = 0x2000, // JS values are equal or higher then this value. - JSPrimitive, - JSObject - } m_state; - QScriptEnginePtr m_engine; - union Value - { - bool m_bool; - qsreal m_number; - JSValueRef m_value; - JSObjectRef m_object; - QString* m_string; - - Value() : m_number(0) {} - Value(bool value) : m_bool(value) {} - Value(int number) : m_number(number) {} - Value(uint number) : m_number(number) {} - Value(qsreal number) : m_number(number) {} - Value(JSValueRef value) : m_value(value) {} - Value(JSObjectRef object) : m_object(object) {} - Value(QString* string) : m_string(string) {} - } u; - - inline State refinedJSValue(); - - inline bool isJSBased() const; - inline bool isNumberBased() const; - inline bool isStringBased() const; -}; - -QScriptValuePrivate* QScriptValuePrivate::get(const QScriptValue& q) { return q.d_ptr.data(); } - -QScriptValue QScriptValuePrivate::get(const QScriptValuePrivate* d) -{ - return QScriptValue(const_cast(d)); -} - -QScriptValue QScriptValuePrivate::get(QScriptValuePrivate* d) -{ - return QScriptValue(d); -} - -QScriptValuePrivate::~QScriptValuePrivate() -{ - if (isJSBased()) - JSValueUnprotect(*m_engine, u.m_value); - else if (isStringBased()) - delete u.m_string; -} - -QScriptValuePrivate::QScriptValuePrivate() - : m_state(Invalid) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(const QString& string) - : m_state(CString) - , u(new QString(string)) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(bool value) - : m_state(CBool) - , u(value) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(int number) - : m_state(CNumber) - , u(number) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(uint number) - : m_state(CNumber) - , u(number) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(qsreal number) - : m_state(CNumber) - , u(number) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value) - : m_state(value == QScriptValue::NullValue ? CNull : CUndefined) -{ -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, int value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(m_engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(m_engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(m_engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(m_engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value) - : m_state(JSPrimitive) - , m_engine(const_cast(engine)) - , u(m_engine->makeJSValue(value)) -{ - Q_ASSERT(engine); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value) - : m_state(JSValue) - , m_engine(const_cast(engine)) - , u(value) -{ - Q_ASSERT(engine); - Q_ASSERT(value); - JSValueProtect(*m_engine, u.m_value); -} - -QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSObjectRef object) - : m_state(JSObject) - , m_engine(const_cast(engine)) - , u(object) -{ - Q_ASSERT(engine); - Q_ASSERT(object); - JSValueProtect(*m_engine, object); -} - -bool QScriptValuePrivate::isValid() const { return m_state != Invalid; } - -bool QScriptValuePrivate::isBool() -{ - switch (m_state) { - case CBool: - return true; - case JSValue: - if (refinedJSValue() != JSPrimitive) - return false; - // Fall-through. - case JSPrimitive: - return JSValueIsBoolean(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isNumber() -{ - switch (m_state) { - case CNumber: - return true; - case JSValue: - if (refinedJSValue() != JSPrimitive) - return false; - // Fall-through. - case JSPrimitive: - return JSValueIsNumber(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isNull() -{ - switch (m_state) { - case CNull: - return true; - case JSValue: - if (refinedJSValue() != JSPrimitive) - return false; - // Fall-through. - case JSPrimitive: - return JSValueIsNull(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isString() -{ - switch (m_state) { - case CString: - return true; - case JSValue: - if (refinedJSValue() != JSPrimitive) - return false; - // Fall-through. - case JSPrimitive: - return JSValueIsString(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isUndefined() -{ - switch (m_state) { - case CUndefined: - return true; - case JSValue: - if (refinedJSValue() != JSPrimitive) - return false; - // Fall-through. - case JSPrimitive: - return JSValueIsUndefined(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isError() -{ - switch (m_state) { - case JSValue: - if (refinedJSValue() != JSObject) - return false; - // Fall-through. - case JSObject: - return m_engine->isError(*this); - default: - return false; - } -} - -bool QScriptValuePrivate::isObject() -{ - switch (m_state) { - case JSValue: - return refinedJSValue() == JSObject; - case JSObject: - return true; - - default: - return false; - } -} - -bool QScriptValuePrivate::isFunction() -{ - switch (m_state) { - case JSValue: - if (refinedJSValue() != JSObject) - return false; - // Fall-through. - case JSObject: - return JSObjectIsFunction(*m_engine, *this); - default: - return false; - } -} - -bool QScriptValuePrivate::isArray() -{ - switch (m_state) { - case JSValue: - if (refinedJSValue() != JSObject) - return false; - // Fall-through. - case JSObject: - return m_engine->isArray(*this); - default: - return false; - } -} - -bool QScriptValuePrivate::isDate() -{ - switch (m_state) { - case JSValue: - if (refinedJSValue() != JSObject) - return false; - // Fall-through. - case JSObject: - return m_engine->isDate(*this); - default: - return false; - } -} - -QString QScriptValuePrivate::toString() const -{ - switch (m_state) { - case Invalid: - return QString(); - case CBool: - return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false"); - case CString: - return *u.m_string; - case CNumber: - return QScriptConverter::toString(u.m_number); - case CNull: - return QString::fromLatin1("null"); - case CUndefined: - return QString::fromLatin1("undefined"); - case JSValue: - case JSPrimitive: - case JSObject: - JSValueRef exception = 0; - JSRetainPtr ptr(Adopt, JSValueToStringCopy(*m_engine, *this, &exception)); - m_engine->setException(exception); - return QScriptConverter::toString(ptr.get()); - } - - Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement."); - return QString(); // Avoid compiler warning. -} - -qsreal QScriptValuePrivate::toNumber() const -{ - switch (m_state) { - case JSValue: - case JSPrimitive: - case JSObject: - { - JSValueRef exception = 0; - qsreal result = JSValueToNumber(*m_engine, *this, &exception); - m_engine->setException(exception); - return result; - } - case CNumber: - return u.m_number; - case CBool: - return u.m_bool ? 1 : 0; - case CNull: - case Invalid: - return 0; - case CUndefined: - return qQNaN(); - case CString: - bool ok; - qsreal result = u.m_string->toDouble(&ok); - if (ok) - return result; - result = u.m_string->toInt(&ok, 0); // Try other bases. - if (ok) - return result; - if (*u.m_string == "Infinity" || *u.m_string == "-Infinity") - return qInf(); - return u.m_string->length() ? qQNaN() : 0; - } - - Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement."); - return 0; // Avoid compiler warning. -} - -bool QScriptValuePrivate::toBool() const -{ - switch (m_state) { - case JSValue: - case JSPrimitive: - return JSValueToBoolean(*m_engine, *this); - case JSObject: - return true; - case CNumber: - return !(qIsNaN(u.m_number) || !u.m_number); - case CBool: - return u.m_bool; - case Invalid: - case CNull: - case CUndefined: - return false; - case CString: - return u.m_string->length(); - } - - Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement."); - return false; // Avoid compiler warning. -} - -qsreal QScriptValuePrivate::toInteger() const -{ - qsreal result = toNumber(); - if (qIsNaN(result)) - return 0; - if (qIsInf(result)) - return result; - return (result > 0) ? qFloor(result) : -1 * qFloor(-result); -} - -qint32 QScriptValuePrivate::toInt32() const -{ - qsreal result = toInteger(); - // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but - // some of these operation are invoked in toInteger subcall. - if (qIsInf(result)) - return 0; - return result; -} - -quint32 QScriptValuePrivate::toUInt32() const -{ - qsreal result = toInteger(); - // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but - // some of these operation are invoked in toInteger subcall. - if (qIsInf(result)) - return 0; - return result; -} - -quint16 QScriptValuePrivate::toUInt16() const -{ - return toInt32(); -} - -/*! - Creates a copy of this value and converts it to an object. If this value is an object - then pointer to this value will be returned. - \attention it should not happen but if this value is bounded to a different engine that the given, the first - one will be used. - \internal - */ -QScriptValuePrivate* QScriptValuePrivate::toObject(QScriptEnginePrivate* engine) -{ - switch (m_state) { - case Invalid: - case CNull: - case CUndefined: - return new QScriptValuePrivate; - case CString: - { - // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(*u.m_string), /* exception */ 0); - Q_ASSERT(object); - return new QScriptValuePrivate(engine, object); - } - case CNumber: - { - // Exception can't occur here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_number), /* exception */ 0); - Q_ASSERT(object); - return new QScriptValuePrivate(engine, object); - } - case CBool: - { - // Exception can't occure here. - JSObjectRef object = JSValueToObject(*engine, engine->makeJSValue(u.m_bool), /* exception */ 0); - Q_ASSERT(object); - return new QScriptValuePrivate(engine, object); - } - case JSValue: - if (refinedJSValue() != JSPrimitive) - break; - // Fall-through. - case JSPrimitive: - { - if (engine != this->engine()) - qWarning("QScriptEngine::toObject: cannot convert value created in a different engine"); - JSValueRef exception = 0; - JSObjectRef object = JSValueToObject(*m_engine, *this, &exception); - if (object) - return new QScriptValuePrivate(m_engine.constData(), object); - else - m_engine->setException(exception, QScriptEnginePrivate::NotNullException); - - } - return new QScriptValuePrivate; - case JSObject: - break; - } - - if (engine != this->engine()) - qWarning("QScriptEngine::toObject: cannot convert value created in a different engine"); - Q_ASSERT(m_state == JSObject); - return this; -} - -/*! - This method is created only for QScriptValue::toObject() purpose which is obsolete. - \internal - */ -QScriptValuePrivate* QScriptValuePrivate::toObject() -{ - if (isJSBased()) - return toObject(m_engine.data()); - - // Without an engine there is not much we can do. - return new QScriptValuePrivate; -} - -QDateTime QScriptValuePrivate::toDateTime() -{ - if (!isDate()) - return QDateTime(); - - JSValueRef exception = 0; - qsreal t = JSValueToNumber(*m_engine, *this, &exception); - - if (exception) { - m_engine->setException(exception, QScriptEnginePrivate::NotNullException); - return QDateTime(); - } - - QDateTime result; - result.setMSecsSinceEpoch(qint64(t)); - return result; -} - -inline QScriptValuePrivate* QScriptValuePrivate::prototype() -{ - if (isObject()) { - JSValueRef prototype = JSObjectGetPrototype(*m_engine, *this); - if (JSValueIsNull(*m_engine, prototype)) - return new QScriptValuePrivate(engine(), prototype); - // The prototype could be either a null or a JSObject, so it is safe to cast the prototype - // to the JSObjectRef here. - return new QScriptValuePrivate(engine(), const_cast(prototype)); - } - return new QScriptValuePrivate; -} - -inline void QScriptValuePrivate::setPrototype(QScriptValuePrivate* prototype) -{ - if (isObject() && prototype->isValid() && (prototype->isObject() || prototype->isNull())) { - if (engine() != prototype->engine()) { - qWarning("QScriptValue::setPrototype() failed: cannot set a prototype created in a different engine"); - return; - } - // FIXME: This could be replaced by a new, faster API - // look at https://bugs.webkit.org/show_bug.cgi?id=40060 - JSObjectSetPrototype(*m_engine, *this, *prototype); - JSValueRef proto = JSObjectGetPrototype(*m_engine, *this); - if (!JSValueIsStrictEqual(*m_engine, proto, *prototype)) - qWarning("QScriptValue::setPrototype() failed: cyclic prototype value"); - } -} - -bool QScriptValuePrivate::equals(QScriptValuePrivate* other) -{ - if (!isValid()) - return !other->isValid(); - - if (!other->isValid()) - return false; - - if (!isJSBased() && !other->isJSBased()) { - switch (m_state) { - case CNull: - case CUndefined: - return other->isUndefined() || other->isNull(); - case CNumber: - switch (other->m_state) { - case CBool: - case CString: - return u.m_number == other->toNumber(); - case CNumber: - return u.m_number == other->u.m_number; - default: - return false; - } - case CBool: - switch (other->m_state) { - case CBool: - return u.m_bool == other->u.m_bool; - case CNumber: - return toNumber() == other->u.m_number; - case CString: - return toNumber() == other->toNumber(); - default: - return false; - } - case CString: - switch (other->m_state) { - case CBool: - return toNumber() == other->toNumber(); - case CNumber: - return toNumber() == other->u.m_number; - case CString: - return *u.m_string == *other->u.m_string; - default: - return false; - } - default: - Q_ASSERT_X(false, "equals()", "Not all states are included in the previous switch statement."); - } - } - - if (isJSBased() && !other->isJSBased()) { - if (!other->assignEngine(engine())) { - qWarning("equals(): Cannot compare to a value created in a different engine"); - return false; - } - } else if (!isJSBased() && other->isJSBased()) { - if (!assignEngine(other->engine())) { - qWarning("equals(): Cannot compare to a value created in a different engine"); - return false; - } - } - - JSValueRef exception = 0; - bool result = JSValueIsEqual(*m_engine, *this, *other, &exception); - m_engine->setException(exception); - return result; -} - -bool QScriptValuePrivate::strictlyEquals(QScriptValuePrivate* other) -{ - if (isJSBased()) { - // We can't compare these two values without binding to the same engine. - if (!other->isJSBased()) { - if (other->assignEngine(engine())) - return JSValueIsStrictEqual(*m_engine, *this, *other); - return false; - } - if (other->engine() != engine()) { - qWarning("strictlyEquals(): Cannot compare to a value created in a different engine"); - return false; - } - return JSValueIsStrictEqual(*m_engine, *this, *other); - } - if (isStringBased()) { - if (other->isStringBased()) - return *u.m_string == *(other->u.m_string); - if (other->isJSBased()) { - assignEngine(other->engine()); - return JSValueIsStrictEqual(*m_engine, *this, *other); - } - } - if (isNumberBased()) { - if (other->isNumberBased()) - return u.m_number == other->u.m_number; - if (other->isJSBased()) { - assignEngine(other->engine()); - return JSValueIsStrictEqual(*m_engine, *this, *other); - } - } - if (!isValid() && !other->isValid()) - return true; - - return false; -} - -inline bool QScriptValuePrivate::instanceOf(QScriptValuePrivate* other) -{ - if (!isJSBased() || !other->isObject()) - return false; - JSValueRef exception = 0; - bool result = JSValueIsInstanceOfConstructor(*m_engine, *this, *other, &exception); - m_engine->setException(exception); - return result; -} - -/*! - Tries to assign \a engine to this value. Returns true on success; otherwise returns false. -*/ -bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) -{ - Q_ASSERT(engine); - JSValueRef value; - switch (m_state) { - case CBool: - value = engine->makeJSValue(u.m_bool); - break; - case CString: - value = engine->makeJSValue(*u.m_string); - delete u.m_string; - break; - case CNumber: - value = engine->makeJSValue(u.m_number); - break; - case CNull: - value = engine->makeJSValue(QScriptValue::NullValue); - break; - case CUndefined: - value = engine->makeJSValue(QScriptValue::UndefinedValue); - break; - default: - if (!isJSBased()) - Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement."); - else - qWarning("JSValue can't be rassigned to an another engine."); - return false; - } - m_engine = engine; - m_state = JSPrimitive; - u.m_value = value; - JSValueProtect(*m_engine, value); - return true; -} - -inline QScriptValuePrivate* QScriptValuePrivate::property(const QString& name, const QScriptValue::ResolveFlags& mode) -{ - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(name)); - return property(propertyName.get(), mode); -} - -inline QScriptValuePrivate* QScriptValuePrivate::property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode) -{ - return property(*name, mode); -} - -inline QScriptValuePrivate* QScriptValuePrivate::property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode) -{ - return property(arrayIndex, mode); -} - -/*! - \internal - This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty. -*/ -inline JSValueRef QScriptValuePrivate::property(quint32 property, JSValueRef* exception) -{ - return JSObjectGetPropertyAtIndex(*m_engine, *this, property, exception); -} - -/*! - \internal - This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty. -*/ -inline JSValueRef QScriptValuePrivate::property(JSStringRef property, JSValueRef* exception) -{ - return JSObjectGetProperty(*m_engine, *this, property, exception); -} - -/*! - \internal - This method was created to unify acccess to hasOwnProperty, same function for an array index - and a property name access. -*/ -inline bool QScriptValuePrivate::hasOwnProperty(quint32 property) -{ - Q_ASSERT(isObject()); - // FIXME it could be faster, but JSC C API doesn't expose needed functionality. - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(QString::number(property))); - return hasOwnProperty(propertyName.get()); -} - -/*! - \internal - This method was created to unify acccess to hasOwnProperty, same function for an array index - and a property name access. -*/ -inline bool QScriptValuePrivate::hasOwnProperty(JSStringRef property) -{ - Q_ASSERT(isObject()); - return m_engine->objectHasOwnProperty(*this, property); -} - -/*! - \internal - This function gets property of an object. - \arg propertyName could be type of quint32 (an array index) or JSStringRef (a property name). -*/ -template -inline QScriptValuePrivate* QScriptValuePrivate::property(T propertyName, const QScriptValue::ResolveFlags& mode) -{ - if (!isObject()) - return new QScriptValuePrivate(); - - if ((mode == QScriptValue::ResolveLocal) && (!hasOwnProperty(propertyName))) - return new QScriptValuePrivate(); - - JSValueRef exception = 0; - JSValueRef value = property(propertyName, &exception); - - if (exception) { - m_engine->setException(exception, QScriptEnginePrivate::NotNullException); - return new QScriptValuePrivate(engine(), exception); - } - if (JSValueIsUndefined(*m_engine, value)) - return new QScriptValuePrivate; - return new QScriptValuePrivate(engine(), value); -} - -inline void QScriptValuePrivate::setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) -{ - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(name)); - setProperty(propertyName.get(), value, flags); -} - -inline void QScriptValuePrivate::setProperty(quint32 arrayIndex, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) -{ - setProperty(arrayIndex, value, flags); -} - -inline void QScriptValuePrivate::setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) -{ - setProperty(*name, value, flags); -} - -/*! - \internal - This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty. -*/ -inline void QScriptValuePrivate::setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception) -{ - Q_ASSERT(isObject()); - if (flags) { - // FIXME This could be better, but JSC C API doesn't expose needed functionality. It is - // not possible to create / modify a property attribute via an array index. - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(QString::number(property))); - JSObjectSetProperty(*m_engine, *this, propertyName.get(), value, flags, exception); - return; - } - JSObjectSetPropertyAtIndex(*m_engine, *this, property, value, exception); -} - -/*! - \internal - This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty. -*/ -inline void QScriptValuePrivate::setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception) -{ - Q_ASSERT(isObject()); - JSObjectSetProperty(*m_engine, *this, property, value, flags, exception); -} - -/*! - \internal - This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex - which doesn't exist now. -*/ -inline void QScriptValuePrivate::deleteProperty(quint32 property, JSValueRef* exception) -{ - // FIXME It could be faster, we need a JSC C API for deleting array index properties. - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(QString::number(property))); - JSObjectDeleteProperty(*m_engine, *this, propertyName.get(), exception); -} - -/*! - \internal - This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex. -*/ -inline void QScriptValuePrivate::deleteProperty(JSStringRef property, JSValueRef* exception) -{ - Q_ASSERT(isObject()); - JSObjectDeleteProperty(*m_engine, *this, property, exception); -} - -template -inline void QScriptValuePrivate::setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) -{ - if (!isObject()) - return; - - if (!value->isJSBased()) - value->assignEngine(engine()); - - JSValueRef exception = 0; - if (!value->isValid()) { - // Remove the property. - deleteProperty(name, &exception); - m_engine->setException(exception); - return; - } - if (m_engine != value->m_engine) { - qWarning("QScriptValue::setProperty() failed: cannot set value created in a different engine"); - return; - } - - setProperty(name, *value, QScriptConverter::toPropertyFlags(flags), &exception); - m_engine->setException(exception); -} - -inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode) -{ - JSRetainPtr propertyName(Adopt, QScriptConverter::toString(name)); - return propertyFlags(propertyName.get(), mode); -} - -inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode) -{ - return propertyFlags(*name, mode); -} - -inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(JSStringRef name, const QScriptValue::ResolveFlags& mode) -{ - unsigned flags = 0; - if (!isObject()) - return QScriptValue::PropertyFlags(flags); - - // FIXME It could be faster and nicer, but new JSC C API should be created. - static JSStringRef objectName = QScriptConverter::toString("Object"); - static JSStringRef propertyDescriptorName = QScriptConverter::toString("getOwnPropertyDescriptor"); - - // FIXME This is dangerous if global object was modified (bug 41839). - JSValueRef exception = 0; - JSObjectRef globalObject = JSContextGetGlobalObject(*m_engine); - JSValueRef objectConstructor = JSObjectGetProperty(*m_engine, globalObject, objectName, &exception); - Q_ASSERT(JSValueIsObject(*m_engine, objectConstructor)); - JSValueRef propertyDescriptorGetter = JSObjectGetProperty(*m_engine, const_cast(objectConstructor), propertyDescriptorName, &exception); - Q_ASSERT(JSValueIsObject(*m_engine, propertyDescriptorGetter)); - - JSValueRef arguments[] = { *this, JSValueMakeString(*m_engine, name) }; - JSObjectRef propertyDescriptor - = const_cast(JSObjectCallAsFunction(*m_engine, - const_cast(propertyDescriptorGetter), - /* thisObject */ 0, - /* argumentCount */ 2, - arguments, - &exception)); - if (exception) { - // Invalid property. - return QScriptValue::PropertyFlags(flags); - } - - if (!JSValueIsObject(*m_engine, propertyDescriptor)) { - // Property isn't owned by this object. - JSObjectRef proto; - if (mode == QScriptValue::ResolveLocal - || ((proto = const_cast(JSObjectGetPrototype(*m_engine, *this))) && JSValueIsNull(*m_engine, proto))) { - return QScriptValue::PropertyFlags(flags); - } - QScriptValuePrivate p(engine(), proto); - return p.propertyFlags(name, QScriptValue::ResolvePrototype); - } - - static JSStringRef writableName = QScriptConverter::toString("writable"); - static JSStringRef configurableName = QScriptConverter::toString("configurable"); - static JSStringRef enumerableName = QScriptConverter::toString("enumerable"); - - bool readOnly = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, writableName, &exception)); - if (!exception && readOnly) - flags |= QScriptValue::ReadOnly; - bool undeletable = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, configurableName, &exception)); - if (!exception && undeletable) - flags |= QScriptValue::Undeletable; - bool skipInEnum = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, enumerableName, &exception)); - if (!exception && skipInEnum) - flags |= QScriptValue::SkipInEnumeration; - - return QScriptValue::PropertyFlags(flags); -} - -QScriptValuePrivate* QScriptValuePrivate::call(const QScriptValuePrivate*, const QScriptValueList& args) -{ - switch (m_state) { - case JSValue: - if (refinedJSValue() != JSObject) - return new QScriptValuePrivate; - // Fall-through. - case JSObject: - { - // Convert all arguments and bind to the engine. - int argc = args.size(); - QVarLengthArray argv(argc); - QScriptValueList::const_iterator i = args.constBegin(); - for (int j = 0; i != args.constEnd(); j++, i++) { - QScriptValuePrivate* value = QScriptValuePrivate::get(*i); - if (!value->assignEngine(engine())) { - qWarning("QScriptValue::call() failed: cannot call function with values created in a different engine"); - return new QScriptValuePrivate; - } - argv[j] = *value; - } - - // Make the call - JSValueRef exception = 0; - JSValueRef result = JSObjectCallAsFunction(*m_engine, *this, /* thisObject */ 0, argc, argv.constData(), &exception); - if (!result && exception) { - m_engine->setException(exception); - return new QScriptValuePrivate(engine(), exception); - } - if (result && !exception) - return new QScriptValuePrivate(engine(), result); - } - // this QSV is not a function <-- !result && !exception. Fall-through. - default: - return new QScriptValuePrivate; - } -} - -QScriptEnginePrivate* QScriptValuePrivate::engine() const -{ - // As long as m_engine is an autoinitializated pointer we can safely return it without - // checking current state. - return m_engine.data(); -} - -QScriptValuePrivate::operator JSValueRef() const -{ - Q_ASSERT(isJSBased()); - Q_ASSERT(u.m_value); - return u.m_value; -} - -QScriptValuePrivate::operator JSObjectRef() const -{ - Q_ASSERT(m_state == JSObject); - Q_ASSERT(u.m_object); - return u.m_object; -} - -/*! - \internal - Refines the state of this QScriptValuePrivate. Returns the new state. -*/ -QScriptValuePrivate::State QScriptValuePrivate::refinedJSValue() -{ - Q_ASSERT(m_state == JSValue); - if (!JSValueIsObject(*m_engine, *this)) { - m_state = JSPrimitive; - } else { - // Difference between JSValueRef and JSObjectRef is only in their type, binarywise it is the same. - // As m_value and m_object are stored in the u union, it is enough to change the m_state only. - m_state = JSObject; - } - return m_state; -} - -/*! - \internal - Returns true if QSV have an engine associated. -*/ -bool QScriptValuePrivate::isJSBased() const { return m_state >= JSValue; } - -/*! - \internal - Returns true if current value of QSV is placed in m_number. -*/ -bool QScriptValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; } - -/*! - \internal - Returns true if current value of QSV is placed in m_string. -*/ -bool QScriptValuePrivate::isStringBased() const { return m_state == CString; } - -#endif // qscriptvalue_p_h