Home | History | Annotate | Download | only in api
      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