1 /* 2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) 3 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. 8 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. 13 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. 18 */ 19 20 #ifndef qscriptengine_p_h 21 #define qscriptengine_p_h 22 23 #include "qscriptconverter_p.h" 24 #include "qscriptengine.h" 25 #include "qscriptoriginalglobalobject_p.h" 26 #include "qscriptstring_p.h" 27 #include "qscriptsyntaxcheckresult_p.h" 28 #include "qscriptvalue.h" 29 #include <JavaScriptCore/JavaScript.h> 30 #include <JavaScriptCore/JSRetainPtr.h> 31 #include <JSBasePrivate.h> 32 #include <QtCore/qshareddata.h> 33 #include <QtCore/qstring.h> 34 #include <QtCore/qstringlist.h> 35 36 class QScriptEngine; 37 class QScriptSyntaxCheckResultPrivate; 38 39 class QScriptEnginePrivate : public QSharedData { 40 public: 41 static QScriptEnginePrivate* get(const QScriptEngine* q) { Q_ASSERT(q); return q->d_ptr.data(); } 42 static QScriptEngine* get(const QScriptEnginePrivate* d) { Q_ASSERT(d); return d->q_ptr; } 43 44 QScriptEnginePrivate(const QScriptEngine*); 45 ~QScriptEnginePrivate(); 46 47 enum SetExceptionFlag { 48 IgnoreNullException = 0x01, 49 NotNullException = 0x02, 50 }; 51 52 QScriptSyntaxCheckResultPrivate* checkSyntax(const QString& program); 53 QScriptValuePrivate* evaluate(const QString& program, const QString& fileName, int lineNumber); 54 QScriptValuePrivate* evaluate(const QScriptProgramPrivate* program); 55 inline JSValueRef evaluate(JSStringRef program, JSStringRef fileName, int lineNumber); 56 57 inline bool hasUncaughtException() const; 58 QScriptValuePrivate* uncaughtException() const; 59 inline void clearExceptions(); 60 inline void setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags = IgnoreNullException); 61 inline int uncaughtExceptionLineNumber() const; 62 inline QStringList uncaughtExceptionBacktrace() const; 63 64 inline void collectGarbage(); 65 inline void reportAdditionalMemoryCost(int cost); 66 67 inline JSValueRef makeJSValue(double number) const; 68 inline JSValueRef makeJSValue(int number) const; 69 inline JSValueRef makeJSValue(uint number) const; 70 inline JSValueRef makeJSValue(const QString& string) const; 71 inline JSValueRef makeJSValue(bool number) const; 72 inline JSValueRef makeJSValue(QScriptValue::SpecialValue value) const; 73 74 QScriptValuePrivate* newFunction(QScriptEngine::FunctionSignature fun, QScriptValuePrivate* prototype, int length); 75 QScriptValuePrivate* newFunction(QScriptEngine::FunctionWithArgSignature fun, void* arg); 76 QScriptValuePrivate* newFunction(JSObjectRef funObject, QScriptValuePrivate* prototype); 77 78 QScriptValuePrivate* newObject() const; 79 QScriptValuePrivate* newArray(uint length); 80 QScriptValuePrivate* newDate(qsreal value); 81 QScriptValuePrivate* globalObject() const; 82 83 inline QScriptStringPrivate* toStringHandle(const QString& str) const; 84 85 inline operator JSGlobalContextRef() const; 86 87 inline bool isDate(JSValueRef value) const; 88 inline bool isArray(JSValueRef value) const; 89 inline bool isError(JSValueRef value) const; 90 inline bool objectHasOwnProperty(JSObjectRef object, JSStringRef property) const; 91 inline QVector<JSStringRef> objectGetOwnPropertyNames(JSObjectRef object) const; 92 93 private: 94 QScriptEngine* q_ptr; 95 JSGlobalContextRef m_context; 96 JSValueRef m_exception; 97 98 QScriptOriginalGlobalObject m_originalGlobalObject; 99 100 JSClassRef m_nativeFunctionClass; 101 JSClassRef m_nativeFunctionWithArgClass; 102 }; 103 104 105 /*! 106 Evaluates given JavaScript program and returns result of the evaluation. 107 \attention this function doesn't take ownership of the parameters. 108 \internal 109 */ 110 JSValueRef QScriptEnginePrivate::evaluate(JSStringRef program, JSStringRef fileName, int lineNumber) 111 { 112 JSValueRef exception; 113 JSValueRef result = JSEvaluateScript(m_context, program, /* Global Object */ 0, fileName, lineNumber, &exception); 114 if (!result) { 115 setException(exception, NotNullException); 116 return exception; // returns an exception 117 } 118 clearExceptions(); 119 return result; 120 } 121 122 bool QScriptEnginePrivate::hasUncaughtException() const 123 { 124 return m_exception; 125 } 126 127 void QScriptEnginePrivate::clearExceptions() 128 { 129 if (m_exception) 130 JSValueUnprotect(m_context, m_exception); 131 m_exception = 0; 132 } 133 134 void QScriptEnginePrivate::setException(JSValueRef exception, const /* SetExceptionFlags */ unsigned flags) 135 { 136 if (!((flags & NotNullException) || exception)) 137 return; 138 Q_ASSERT(exception); 139 140 if (m_exception) 141 JSValueUnprotect(m_context, m_exception); 142 JSValueProtect(m_context, exception); 143 m_exception = exception; 144 } 145 146 int QScriptEnginePrivate::uncaughtExceptionLineNumber() const 147 { 148 if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception)) 149 return -1; 150 151 JSValueRef exception = 0; 152 JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line")); 153 JSValueRef lineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception); 154 int result = JSValueToNumber(m_context, lineNumber, &exception); 155 return exception ? -1 : result; 156 } 157 158 QStringList QScriptEnginePrivate::uncaughtExceptionBacktrace() const 159 { 160 if (!hasUncaughtException() || !JSValueIsObject(m_context, m_exception)) 161 return QStringList(); 162 163 JSValueRef exception = 0; 164 JSRetainPtr<JSStringRef> fileNamePropertyName(Adopt, QScriptConverter::toString("sourceURL")); 165 JSRetainPtr<JSStringRef> lineNumberPropertyName(Adopt, QScriptConverter::toString("line")); 166 JSValueRef jsFileName = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), fileNamePropertyName.get(), &exception); 167 JSValueRef jsLineNumber = JSObjectGetProperty(m_context, const_cast<JSObjectRef>(m_exception), lineNumberPropertyName.get(), &exception); 168 JSRetainPtr<JSStringRef> fileName(Adopt, JSValueToStringCopy(m_context, jsFileName, &exception)); 169 int lineNumber = JSValueToNumber(m_context, jsLineNumber, &exception); 170 return QStringList(QString::fromLatin1("<anonymous>()@%0:%1") 171 .arg(QScriptConverter::toString(fileName.get())) 172 .arg(QScriptConverter::toString(exception ? -1 : lineNumber))); 173 } 174 175 void QScriptEnginePrivate::collectGarbage() 176 { 177 JSGarbageCollect(m_context); 178 } 179 180 void QScriptEnginePrivate::reportAdditionalMemoryCost(int cost) 181 { 182 if (cost > 0) 183 JSReportExtraMemoryCost(m_context, cost); 184 } 185 186 JSValueRef QScriptEnginePrivate::makeJSValue(double number) const 187 { 188 return JSValueMakeNumber(m_context, number); 189 } 190 191 JSValueRef QScriptEnginePrivate::makeJSValue(int number) const 192 { 193 return JSValueMakeNumber(m_context, number); 194 } 195 196 JSValueRef QScriptEnginePrivate::makeJSValue(uint number) const 197 { 198 return JSValueMakeNumber(m_context, number); 199 } 200 201 JSValueRef QScriptEnginePrivate::makeJSValue(const QString& string) const 202 { 203 JSStringRef tmp = QScriptConverter::toString(string); 204 JSValueRef result = JSValueMakeString(m_context, tmp); 205 JSStringRelease(tmp); 206 return result; 207 } 208 209 JSValueRef QScriptEnginePrivate::makeJSValue(bool value) const 210 { 211 return JSValueMakeBoolean(m_context, value); 212 } 213 214 JSValueRef QScriptEnginePrivate::makeJSValue(QScriptValue::SpecialValue value) const 215 { 216 if (value == QScriptValue::NullValue) 217 return JSValueMakeNull(m_context); 218 return JSValueMakeUndefined(m_context); 219 } 220 221 QScriptStringPrivate* QScriptEnginePrivate::toStringHandle(const QString& str) const 222 { 223 return new QScriptStringPrivate(str); 224 } 225 226 QScriptEnginePrivate::operator JSGlobalContextRef() const 227 { 228 Q_ASSERT(this); 229 return m_context; 230 } 231 232 bool QScriptEnginePrivate::isDate(JSValueRef value) const 233 { 234 return m_originalGlobalObject.isDate(value); 235 } 236 237 bool QScriptEnginePrivate::isArray(JSValueRef value) const 238 { 239 return m_originalGlobalObject.isArray(value); 240 } 241 242 bool QScriptEnginePrivate::isError(JSValueRef value) const 243 { 244 return m_originalGlobalObject.isError(value); 245 } 246 247 inline bool QScriptEnginePrivate::objectHasOwnProperty(JSObjectRef object, JSStringRef property) const 248 { 249 // FIXME We need a JSC C API function for this. 250 return m_originalGlobalObject.objectHasOwnProperty(object, property); 251 } 252 253 inline QVector<JSStringRef> QScriptEnginePrivate::objectGetOwnPropertyNames(JSObjectRef object) const 254 { 255 // FIXME We can't use C API function JSObjectGetPropertyNames as it returns only enumerable properties. 256 return m_originalGlobalObject.objectGetOwnPropertyNames(object); 257 } 258 259 #endif 260