From c6cbece9baec95d54d85a26f439ed4e7274ca3fd Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 9 Oct 2009 18:52:01 +0200 Subject: some preliminary work on QScriptProgram --- src/script/api/api.pri | 3 + src/script/api/qscriptengine.cpp | 73 +++++++++++++++++++++ src/script/api/qscriptprogram.cpp | 134 ++++++++++++++++++++++++++++++++++++++ src/script/api/qscriptprogram.h | 74 +++++++++++++++++++++ src/script/api/qscriptprogram_p.h | 88 +++++++++++++++++++++++++ 5 files changed, 372 insertions(+) create mode 100644 src/script/api/qscriptprogram.cpp create mode 100644 src/script/api/qscriptprogram.h create mode 100644 src/script/api/qscriptprogram_p.h diff --git a/src/script/api/api.pri b/src/script/api/api.pri index 17ec9b6..aebadd5 100644 --- a/src/script/api/api.pri +++ b/src/script/api/api.pri @@ -6,6 +6,7 @@ SOURCES += \ $$PWD/qscriptengine.cpp \ $$PWD/qscriptengineagent.cpp \ $$PWD/qscriptextensionplugin.cpp \ + $$PWD/qscriptprogram.cpp \ $$PWD/qscriptstring.cpp \ $$PWD/qscriptvalue.cpp \ $$PWD/qscriptvalueiterator.cpp \ @@ -23,6 +24,8 @@ HEADERS += \ $$PWD/qscriptengineagent_p.h \ $$PWD/qscriptextensioninterface.h \ $$PWD/qscriptextensionplugin.h \ + $$PWD/qscriptprogram.h \ + $$PWD/qscriptprogram_p.h \ $$PWD/qscriptstring.h \ $$PWD/qscriptstring_p.h \ $$PWD/qscriptvalue.h \ diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index b1f36be..b11c276 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -51,6 +51,8 @@ #include "qscriptvalue_p.h" #include "qscriptvalueiterator.h" #include "qscriptclass.h" +#include "qscriptprogram.h" +#include "qscriptprogram_p.h" #include "qdebug.h" #include @@ -2214,6 +2216,77 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file return d->scriptValueFromJSCValue(result); } +QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) +{ + Q_D(QScriptEngine); + JSC::UString jscProgram = program; + JSC::UString jscFileName = fileName; + WTF::PassRefPtr provider + = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d); + JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null. + + JSC::ExecState* exec = d->currentFrame; + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + JSC::EvalExecutable *executable = new JSC::EvalExecutable(exec, source); + JSC::JSObject* error = executable->compile(exec, exec->scopeChain()); + if (error != 0) { + delete executable; + return QScriptProgram(); + } + return QScriptProgramPrivate::create(d, executable, provider->asID()); +} + +QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) +{ + Q_D(QScriptEngine); + QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program); + if (!program_d || !program_d->engine || !program_d->executable) + return QScriptValue(); + + JSC::ExecState* exec = d->currentFrame; + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + intptr_t sourceId = program_d->sourceId; + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + JSC::JSValue thisValue = d->thisForContext(exec); + JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + JSC::JSValue exceptionValue; + d->timeoutChecker()->setShouldAbort(false); + if (d->processEventsInterval > 0) + d->timeoutChecker()->reset(); + JSC::JSValue result = exec->interpreter()->execute(program_d->executable, exec, thisObject, exec->scopeChain(), &exceptionValue); + + if (d->timeoutChecker()->shouldAbort()) { + if (d->abortResult.isError()) + exec->setException(d->scriptValueToJSCValue(d->abortResult)); + + if (debugger) + debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId); + + return d->abortResult; + } + + if (exceptionValue) { + exec->setException(exceptionValue); + + if (debugger) + debugger->evaluateStop(exceptionValue, sourceId); + + return d->scriptValueFromJSCValue(exceptionValue); + } + + if (debugger) + debugger->evaluateStop(result, sourceId); + + Q_ASSERT(!exec->hadException()); + return d->scriptValueFromJSCValue(result); +} /*! Returns the current context. diff --git a/src/script/api/qscriptprogram.cpp b/src/script/api/qscriptprogram.cpp new file mode 100644 index 0000000..2746c44 --- /dev/null +++ b/src/script/api/qscriptprogram.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscriptprogram.h" +#include "qscriptprogram_p.h" +#include "qscriptengine.h" +#include "qscriptengine_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.6 + \class QScriptProgram + + \brief The QScriptProgram class ... + + \ingroup script + +*/ + +QScriptProgramPrivate::QScriptProgramPrivate(QScriptEnginePrivate *e, + JSC::EvalExecutable *x, + intptr_t id) + : engine(e), executable(x), sourceId(id) +{ + ref = 0; +} + +QScriptProgramPrivate::~QScriptProgramPrivate() +{ +} + +QScriptProgramPrivate *QScriptProgramPrivate::get(const QScriptProgram &q) +{ + return const_cast(q.d_func()); +} + +QScriptProgram QScriptProgramPrivate::create(QScriptEnginePrivate *engine, + JSC::EvalExecutable *executable, + intptr_t sourceId) +{ + QScriptProgramPrivate *d = new QScriptProgramPrivate(engine, executable, sourceId); + QScriptProgram result; + result.d_ptr = d; + return result; +} + +/*! + Constructs an invalid QScriptProgram. +*/ +QScriptProgram::QScriptProgram() + : d_ptr(0) +{ +} + +/*! + Constructs a new QScriptProgram that is a copy of \a other. +*/ +QScriptProgram::QScriptProgram(const QScriptProgram &other) + : d_ptr(other.d_ptr) +{ +} + +/*! + Destroys this QScriptProgram. +*/ +QScriptProgram::~QScriptProgram() +{ + Q_D(QScriptProgram); + // if (d->engine && (d->ref == 1)) + // d->engine->unregisterScriptProgram(d); +} + +/*! + Assigns the \a other value to this QScriptProgram. +*/ +QScriptProgram &QScriptProgram::operator=(const QScriptProgram &other) +{ + // if (d_func() && d_func()->engine && (d_func()->ref == 1)) + // d_func()->engine->unregisterScriptProgram(d_func()); + // } + d_ptr = other.d_ptr; + return *this; +} + +/*! + Returns true if this QScriptProgram is valid; otherwise + returns false. +*/ +bool QScriptProgram::isValid() const +{ + Q_D(const QScriptProgram); + return (d && d->engine); +} + +QT_END_NAMESPACE diff --git a/src/script/api/qscriptprogram.h b/src/script/api/qscriptprogram.h new file mode 100644 index 0000000..6c2ba47 --- /dev/null +++ b/src/script/api/qscriptprogram.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTPROGRAM_H +#define QSCRIPTPROGRAM_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QScriptProgramPrivate; +class Q_SCRIPT_EXPORT QScriptProgram +{ +public: + QScriptProgram(); + QScriptProgram(const QScriptProgram &other); + ~QScriptProgram(); + + QScriptProgram &operator=(const QScriptProgram &other); + + bool isValid() const; + +private: + QExplicitlySharedDataPointer d_ptr; + Q_DECLARE_PRIVATE(QScriptProgram) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSCRIPTPROGRAM_H diff --git a/src/script/api/qscriptprogram_p.h b/src/script/api/qscriptprogram_p.h new file mode 100644 index 0000000..fe06b38 --- /dev/null +++ b/src/script/api/qscriptprogram_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTPROGRAM_P_H +#define QSCRIPTPROGRAM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +namespace JSC +{ + class EvalExecutable; +} + +QT_BEGIN_NAMESPACE + +class QScriptEnginePrivate; + +class QScriptProgramPrivate +{ +public: + QScriptProgramPrivate(QScriptEnginePrivate*, + JSC::EvalExecutable*, + intptr_t); + ~QScriptProgramPrivate(); + + static QScriptProgramPrivate *get(const QScriptProgram &q); + static QScriptProgram create(QScriptEnginePrivate*, + JSC::EvalExecutable*, + intptr_t); + + QBasicAtomicInt ref; + QScriptEnginePrivate *engine; + JSC::EvalExecutable *executable; + intptr_t sourceId; +}; + +QT_END_NAMESPACE + +#endif -- cgit v0.12 From 9c1e8178aca83e2a9e3c7aa8a9a9c91a6fa4ec71 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 09:37:46 +0200 Subject: add compile() and evaluate() functions to public api --- src/script/api/qscriptengine.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index 701f9c6..c58bb7c 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -67,6 +67,7 @@ class QDateTime; class QScriptClass; class QScriptEngineAgent; class QScriptEnginePrivate; +class QScriptProgram; #ifndef QT_NO_QOBJECT @@ -166,6 +167,9 @@ public: QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QScriptProgram compile(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QScriptValue evaluate(const QScriptProgram &program); + bool isEvaluating() const; void abortEvaluation(const QScriptValue &result = QScriptValue()); -- cgit v0.12 From 3c2f239b974a776c05ab0886925db1c8dca19d4d Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 09:38:56 +0200 Subject: delete the executable when the program is destroyed --- src/script/api/qscriptprogram.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/script/api/qscriptprogram.cpp b/src/script/api/qscriptprogram.cpp index 2746c44..96760ba 100644 --- a/src/script/api/qscriptprogram.cpp +++ b/src/script/api/qscriptprogram.cpp @@ -44,14 +44,16 @@ #include "qscriptengine.h" #include "qscriptengine_p.h" +#include "Executable.h" + QT_BEGIN_NAMESPACE /*! + \internal + \since 4.6 \class QScriptProgram - \brief The QScriptProgram class ... - \ingroup script */ @@ -66,6 +68,7 @@ QScriptProgramPrivate::QScriptProgramPrivate(QScriptEnginePrivate *e, QScriptProgramPrivate::~QScriptProgramPrivate() { + delete executable; } QScriptProgramPrivate *QScriptProgramPrivate::get(const QScriptProgram &q) -- cgit v0.12 From 980291d7d79022c31f900f67e0422da1a8abb0a0 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 09:39:14 +0200 Subject: separate the logic shared by evaluate(QString) and evaluate(QScriptProgram) Introduce helper function evaluateHelper(). --- src/script/api/qscriptengine.cpp | 124 ++++++++++++++++++--------------------- src/script/api/qscriptengine_p.h | 4 ++ 2 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index b11c276..25f815f 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1188,6 +1188,45 @@ void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent) } } +QScriptValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, JSC::Debugger* debugger, + intptr_t sourceId, JSC::EvalExecutable *executable) +{ + JSC::JSValue thisValue = thisForContext(exec); + JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) + ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + JSC::JSValue exceptionValue; + timeoutChecker()->setShouldAbort(false); + if (processEventsInterval > 0) + timeoutChecker()->reset(); + + JSC::JSValue result = exec->interpreter()->execute(executable, exec, thisObject, exec->scopeChain(), &exceptionValue); + + if (timeoutChecker()->shouldAbort()) { + if (abortResult.isError()) + exec->setException(scriptValueToJSCValue(abortResult)); + + if (debugger) + debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId); + + return abortResult; + } + + if (exceptionValue) { + exec->setException(exceptionValue); + + if (debugger) + debugger->evaluateStop(exceptionValue, sourceId); + + return scriptValueFromJSCValue(exceptionValue); + } + + if (debugger) + debugger->evaluateStop(result, sourceId); + + Q_ASSERT(!exec->hadException()); + return scriptValueFromJSCValue(result); +} + #ifndef QT_NO_QOBJECT JSC::JSValue QScriptEnginePrivate::newQObject( @@ -2153,8 +2192,6 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file QBoolBlocker inEval(d->inEval, true); currentContext()->activationObject(); //force the creation of a context for native function; - JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); - JSC::UString jscProgram = program; JSC::UString jscFileName = fileName; JSC::ExecState* exec = d->currentFrame; @@ -2163,6 +2200,7 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file intptr_t sourceId = provider->asID(); JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null. + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); if (debugger) debugger->evaluateStart(sourceId); @@ -2182,40 +2220,13 @@ QScriptValue QScriptEngine::evaluate(const QString &program, const QString &file return d->scriptValueFromJSCValue(error); } - JSC::JSValue thisValue = d->thisForContext(exec); - JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); - JSC::JSValue exceptionValue; - d->timeoutChecker()->setShouldAbort(false); - if (d->processEventsInterval > 0) - d->timeoutChecker()->reset(); - JSC::JSValue result = exec->interpreter()->execute(&executable, exec, thisObject, exec->scopeChain(), &exceptionValue); - - if (d->timeoutChecker()->shouldAbort()) { - if (d->abortResult.isError()) - exec->setException(d->scriptValueToJSCValue(d->abortResult)); - - if (debugger) - debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId); - - return d->abortResult; - } - - if (exceptionValue) { - exec->setException(exceptionValue); - - if (debugger) - debugger->evaluateStop(exceptionValue, sourceId); - - return d->scriptValueFromJSCValue(exceptionValue); - } - - if (debugger) - debugger->evaluateStop(result, sourceId); - - Q_ASSERT(!exec->hadException()); - return d->scriptValueFromJSCValue(result); + return d->evaluateHelper(exec, debugger, sourceId, &executable); } +/*! + \internal + \since 4.6 +*/ QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) { Q_D(QScriptEngine); @@ -2238,6 +2249,10 @@ QScriptProgram QScriptEngine::compile(const QString &program, const QString &fil return QScriptProgramPrivate::create(d, executable, provider->asID()); } +/*! + \internal + \since 4.6 +*/ QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) { Q_D(QScriptEngine); @@ -2245,47 +2260,20 @@ QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) if (!program_d || !program_d->engine || !program_d->executable) return QScriptValue(); - JSC::ExecState* exec = d->currentFrame; - exec->clearException(); - JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + JSC::JSLock lock(false); + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; intptr_t sourceId = program_d->sourceId; JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); if (debugger) debugger->evaluateStart(sourceId); - JSC::JSValue thisValue = d->thisForContext(exec); - JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); - JSC::JSValue exceptionValue; - d->timeoutChecker()->setShouldAbort(false); - if (d->processEventsInterval > 0) - d->timeoutChecker()->reset(); - JSC::JSValue result = exec->interpreter()->execute(program_d->executable, exec, thisObject, exec->scopeChain(), &exceptionValue); - - if (d->timeoutChecker()->shouldAbort()) { - if (d->abortResult.isError()) - exec->setException(d->scriptValueToJSCValue(d->abortResult)); - - if (debugger) - debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId); - - return d->abortResult; - } - - if (exceptionValue) { - exec->setException(exceptionValue); - - if (debugger) - debugger->evaluateStop(exceptionValue, sourceId); - - return d->scriptValueFromJSCValue(exceptionValue); - } - - if (debugger) - debugger->evaluateStop(result, sourceId); + JSC::ExecState* exec = d->currentFrame; + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); - Q_ASSERT(!exec->hadException()); - return d->scriptValueFromJSCValue(result); + return d->evaluateHelper(exec, debugger, sourceId, program_d->executable); } /*! diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index f1fc135..c7e9f2a 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -70,6 +70,7 @@ namespace JSC { + class EvalExecutable; class ExecState; typedef ExecState CallFrame; class JSCell; @@ -196,6 +197,9 @@ public: const QByteArray &targetType, void **result); + QScriptValue evaluateHelper(JSC::ExecState *exec, JSC::Debugger* debugger, + intptr_t sourceId, JSC::EvalExecutable *executable); + QScript::QObjectData *qobjectData(QObject *object); void disposeQObject(QObject *object); void emitSignalHandlerException(); -- cgit v0.12 From e1ae391b679c188f8f9c86dd4af0c26300b14bd6 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 10:21:37 +0200 Subject: add getter functions and comparison operators to QScriptProgram --- src/script/api/qscriptprogram.cpp | 53 +++++++++++++++++++++++++++++++++++++++ src/script/api/qscriptprogram.h | 7 ++++++ 2 files changed, 60 insertions(+) diff --git a/src/script/api/qscriptprogram.cpp b/src/script/api/qscriptprogram.cpp index 96760ba..9f88363 100644 --- a/src/script/api/qscriptprogram.cpp +++ b/src/script/api/qscriptprogram.cpp @@ -134,4 +134,57 @@ bool QScriptProgram::isValid() const return (d && d->engine); } +/*! + Returns the source code of this program. +*/ +QString QScriptProgram::sourceCode() const +{ + Q_D(const QScriptProgram); + if (!d) + return QString(); + return d->executable->source().toString(); +} + +/*! + Returns the filename associated with this program. +*/ +QString QScriptProgram::fileName() const +{ + Q_D(const QScriptProgram); + if (!d) + return QString(); + return d->executable->sourceURL(); +} + +/*! + Returns the line number associated with this program. +*/ +int QScriptProgram::lineNumber() const +{ + Q_D(const QScriptProgram); + if (!d) + return -1; + return d->executable->lineNo(); +} + +/*! + Returns true if this QScriptProgram is equal to \a other; + otherwise returns false. +*/ +bool QScriptProgram::operator==(const QScriptProgram &other) const +{ + return (sourceCode() == other.sourceCode()) + && (fileName() == other.fileName()) + && (lineNumber() == other.lineNumber()); +} + +/*! + Returns true if this QScriptProgram is not equal to \a other; + otherwise returns false. +*/ +bool QScriptProgram::operator!=(const QScriptProgram &other) const +{ + return !operator==(other); +} + QT_END_NAMESPACE diff --git a/src/script/api/qscriptprogram.h b/src/script/api/qscriptprogram.h index 6c2ba47..b6782b8 100644 --- a/src/script/api/qscriptprogram.h +++ b/src/script/api/qscriptprogram.h @@ -62,6 +62,13 @@ public: bool isValid() const; + QString sourceCode() const; + QString fileName() const; + int lineNumber() const; + + bool operator==(const QScriptProgram &other) const; + bool operator!=(const QScriptProgram &other) const; + private: QExplicitlySharedDataPointer d_ptr; Q_DECLARE_PRIVATE(QScriptProgram) -- cgit v0.12 From b824fc37d618e55bd128bacebb78dc3770c73264 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 10:22:08 +0200 Subject: add some autotests for QScriptProgram --- tests/auto/qscriptengine/tst_qscriptengine.cpp | 81 ++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 25ee00f..c00bde6 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -151,6 +152,7 @@ private slots: void installTranslatorFunctions(); void functionScopes(); void nativeFunctionScopes(); + void compileAndEvaluate(); void qRegExpInport_data(); void qRegExpInport(); @@ -4289,6 +4291,85 @@ void tst_QScriptEngine::nativeFunctionScopes() } } +void tst_QScriptEngine::compileAndEvaluate() +{ + QScriptEngine eng; + + { + QString code("1 + 2"); + QString fileName("hello.js"); + int lineNumber(123); + QScriptProgram program = eng.compile(code, fileName, lineNumber); + QVERIFY(program.isValid()); + QCOMPARE(program.sourceCode(), code); + QCOMPARE(program.fileName(), fileName); + QCOMPARE(program.lineNumber(), lineNumber); + + QScriptValue expected = eng.evaluate(code); + QScriptValue ret = eng.evaluate(program); + QVERIFY(ret.equals(expected)); + } + + // Program that accesses variable in the scope + { + QScriptProgram program = eng.compile("a"); + QVERIFY(program.isValid()); + { + QScriptValue ret = eng.evaluate(program); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a")); + } + + QScriptValue obj = eng.newObject(); + obj.setProperty("a", 123); + QScriptContext *ctx = eng.currentContext(); + ctx->pushScope(obj); + { + QScriptValue ret = eng.evaluate(program); + QVERIFY(!ret.isError()); + QVERIFY(ret.equals(obj.property("a"))); + } + + obj.setProperty("a", QScriptValue()); + { + QScriptValue ret = eng.evaluate(program); + QVERIFY(ret.isError()); + } + + QScriptValue obj2 = eng.newObject(); + obj2.setProperty("a", 456); + ctx->pushScope(obj2); + { + QScriptValue ret = eng.evaluate(program); + QVERIFY(!ret.isError()); + QVERIFY(ret.equals(obj2.property("a"))); + } + + ctx->popScope(); + } + + // Program that creates closure + { + QScriptProgram program = eng.compile("(function() { var count = 0; return function() { return count++; }; })"); + QVERIFY(program.isValid()); + QScriptValue createCounter = eng.evaluate(program); + QVERIFY(createCounter.isFunction()); + QScriptValue counter = createCounter.call(); + QVERIFY(counter.isFunction()); + { + QScriptValue ret = counter.call(); + QVERIFY(ret.isNumber()); + } + QScriptValue counter2 = createCounter.call(); + QVERIFY(counter2.isFunction()); + QVERIFY(!counter2.equals(counter)); + { + QScriptValue ret = counter2.call(); + QVERIFY(ret.isNumber()); + } + } +} + static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; } void tst_QScriptEngine::qRegExpInport_data() -- cgit v0.12 From c21d3a0094b0692f2f888b04e258229234200e3c Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 14:45:13 +0200 Subject: Refactor QScriptProgram and related API Get rid of QScriptEngine::compile(); you pass arguments to the QScriptProgram constructor instead. evaluate() will lazily compile the program the first time it is evaluated, then use the cached, compiled form on subsequent calls. --- src/script/api/qscriptengine.cpp | 118 ++++++++------------- src/script/api/qscriptengine.h | 1 - src/script/api/qscriptengine_p.h | 5 +- src/script/api/qscriptprogram.cpp | 61 +++++++---- src/script/api/qscriptprogram.h | 7 +- src/script/api/qscriptprogram_p.h | 21 ++-- tests/auto/qscriptengine/tst_qscriptengine.cpp | 45 ++++++-- .../qscriptengineagent/tst_qscriptengineagent.cpp | 87 +++++++++++++++ 8 files changed, 231 insertions(+), 114 deletions(-) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 25f815f..9bc4d6b 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1188,9 +1188,36 @@ void QScriptEnginePrivate::agentDeleted(QScriptEngineAgent *agent) } } -QScriptValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, JSC::Debugger* debugger, - intptr_t sourceId, JSC::EvalExecutable *executable) +JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t sourceId, + JSC::EvalExecutable *executable, + bool &compile) { + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEvalBlocker(inEval, true); + q_func()->currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::Debugger* debugger = originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + if (compile) { + JSC::JSObject* error = executable->compile(exec, exec->scopeChain()); + if (error) { + compile = false; + exec->setException(error); + + if (debugger) { + debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false); + debugger->evaluateStop(error, sourceId); + } + + return error; + } + } + JSC::JSValue thisValue = thisForContext(exec); JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); @@ -1208,7 +1235,7 @@ QScriptValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, JSC::Deb if (debugger) debugger->evaluateStop(scriptValueToJSCValue(abortResult), sourceId); - return abortResult; + return scriptValueToJSCValue(abortResult); } if (exceptionValue) { @@ -1217,14 +1244,14 @@ QScriptValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, JSC::Deb if (debugger) debugger->evaluateStop(exceptionValue, sourceId); - return scriptValueFromJSCValue(exceptionValue); + return exceptionValue; } if (debugger) debugger->evaluateStop(result, sourceId); Q_ASSERT(!exec->hadException()); - return scriptValueFromJSCValue(result); + return result; } #ifndef QT_NO_QOBJECT @@ -2187,66 +2214,15 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra QScriptValue QScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber) { Q_D(QScriptEngine); - - JSC::JSLock lock(false); // ### hmmm - QBoolBlocker inEval(d->inEval, true); - currentContext()->activationObject(); //force the creation of a context for native function; - - JSC::UString jscProgram = program; - JSC::UString jscFileName = fileName; - JSC::ExecState* exec = d->currentFrame; WTF::PassRefPtr provider - = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d); + = QScript::UStringSourceProviderWithFeedback::create(program, fileName, lineNumber, d); intptr_t sourceId = provider->asID(); JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null. - JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); - if (debugger) - debugger->evaluateStart(sourceId); - - exec->clearException(); - JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); - - JSC::EvalExecutable executable(exec, source); - JSC::JSObject* error = executable.compile(exec, exec->scopeChain()); - if (error) { - exec->setException(error); - - if (debugger) { - debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, error), sourceId, false); - debugger->evaluateStop(error, sourceId); - } - - return d->scriptValueFromJSCValue(error); - } - - return d->evaluateHelper(exec, debugger, sourceId, &executable); -} - -/*! - \internal - \since 4.6 -*/ -QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) -{ - Q_D(QScriptEngine); - JSC::UString jscProgram = program; - JSC::UString jscFileName = fileName; - WTF::PassRefPtr provider - = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d); - JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null. - JSC::ExecState* exec = d->currentFrame; - exec->clearException(); - JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); - - JSC::EvalExecutable *executable = new JSC::EvalExecutable(exec, source); - JSC::JSObject* error = executable->compile(exec, exec->scopeChain()); - if (error != 0) { - delete executable; - return QScriptProgram(); - } - return QScriptProgramPrivate::create(d, executable, provider->asID()); + JSC::EvalExecutable executable(exec, source); + bool compile = true; + return d->scriptValueFromJSCValue(d->evaluateHelper(exec, sourceId, &executable, compile)); } /*! @@ -2257,23 +2233,17 @@ QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) { Q_D(QScriptEngine); QScriptProgramPrivate *program_d = QScriptProgramPrivate::get(program); - if (!program_d || !program_d->engine || !program_d->executable) + if (!program_d) return QScriptValue(); - JSC::JSLock lock(false); - QBoolBlocker inEval(d->inEval, true); - currentContext()->activationObject(); //force the creation of a context for native function; - - intptr_t sourceId = program_d->sourceId; - JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); - if (debugger) - debugger->evaluateStart(sourceId); - JSC::ExecState* exec = d->currentFrame; - exec->clearException(); - JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); - - return d->evaluateHelper(exec, debugger, sourceId, program_d->executable); + JSC::EvalExecutable *executable = program_d->executable(exec, d); + bool compile = !program_d->isCompiled; + JSC::JSValue result = d->evaluateHelper(exec, program_d->sourceId, + executable, compile); + if (compile) + program_d->isCompiled = true; + return d->scriptValueFromJSCValue(result); } /*! diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index c58bb7c..3f438da 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -167,7 +167,6 @@ public: QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); - QScriptProgram compile(const QString &program, const QString &fileName = QString(), int lineNumber = 1); QScriptValue evaluate(const QScriptProgram &program); bool isEvaluating() const; diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index c7e9f2a..22de29c 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -197,8 +197,9 @@ public: const QByteArray &targetType, void **result); - QScriptValue evaluateHelper(JSC::ExecState *exec, JSC::Debugger* debugger, - intptr_t sourceId, JSC::EvalExecutable *executable); + JSC::JSValue evaluateHelper(JSC::ExecState *exec, intptr_t sourceId, + JSC::EvalExecutable *executable, + bool &compile); QScript::QObjectData *qobjectData(QObject *object); void disposeQObject(QObject *object); diff --git a/src/script/api/qscriptprogram.cpp b/src/script/api/qscriptprogram.cpp index 9f88363..3ea4fa7 100644 --- a/src/script/api/qscriptprogram.cpp +++ b/src/script/api/qscriptprogram.cpp @@ -58,17 +58,18 @@ QT_BEGIN_NAMESPACE */ -QScriptProgramPrivate::QScriptProgramPrivate(QScriptEnginePrivate *e, - JSC::EvalExecutable *x, - intptr_t id) - : engine(e), executable(x), sourceId(id) +QScriptProgramPrivate::QScriptProgramPrivate(const QString &src, + const QString &fn, + int ln) + : sourceCode(src), fileName(fn), lineNumber(ln), + engine(0), _executable(0), sourceId(-1), isCompiled(false) { ref = 0; } QScriptProgramPrivate::~QScriptProgramPrivate() { - delete executable; + delete _executable; } QScriptProgramPrivate *QScriptProgramPrivate::get(const QScriptProgram &q) @@ -76,18 +77,26 @@ QScriptProgramPrivate *QScriptProgramPrivate::get(const QScriptProgram &q) return const_cast(q.d_func()); } -QScriptProgram QScriptProgramPrivate::create(QScriptEnginePrivate *engine, - JSC::EvalExecutable *executable, - intptr_t sourceId) +JSC::EvalExecutable *QScriptProgramPrivate::executable(JSC::ExecState *exec, + QScriptEnginePrivate *eng) { - QScriptProgramPrivate *d = new QScriptProgramPrivate(engine, executable, sourceId); - QScriptProgram result; - result.d_ptr = d; - return result; + if (_executable) { + if (eng == engine) + return _executable; + delete _executable; + } + WTF::PassRefPtr provider + = QScript::UStringSourceProviderWithFeedback::create(sourceCode, fileName, lineNumber, eng); + sourceId = provider->asID(); + JSC::SourceCode source(provider, lineNumber); //after construction of SourceCode provider variable will be null. + _executable = new JSC::EvalExecutable(exec, source); + engine = eng; + isCompiled = false; + return _executable; } /*! - Constructs an invalid QScriptProgram. + Constructs a null QScriptProgram. */ QScriptProgram::QScriptProgram() : d_ptr(0) @@ -95,6 +104,17 @@ QScriptProgram::QScriptProgram() } /*! + Constructs a new QScriptProgram with the given \a sourceCode, \a + fileName and \a lineNumber. +*/ +QScriptProgram::QScriptProgram(const QString &sourceCode, + const QString fileName, + int lineNumber) + : d_ptr(new QScriptProgramPrivate(sourceCode, fileName, lineNumber)) +{ +} + +/*! Constructs a new QScriptProgram that is a copy of \a other. */ QScriptProgram::QScriptProgram(const QScriptProgram &other) @@ -125,13 +145,13 @@ QScriptProgram &QScriptProgram::operator=(const QScriptProgram &other) } /*! - Returns true if this QScriptProgram is valid; otherwise + Returns true if this QScriptProgram is null; otherwise returns false. */ -bool QScriptProgram::isValid() const +bool QScriptProgram::isNull() const { Q_D(const QScriptProgram); - return (d && d->engine); + return (d == 0); } /*! @@ -142,7 +162,7 @@ QString QScriptProgram::sourceCode() const Q_D(const QScriptProgram); if (!d) return QString(); - return d->executable->source().toString(); + return d->sourceCode; } /*! @@ -153,7 +173,7 @@ QString QScriptProgram::fileName() const Q_D(const QScriptProgram); if (!d) return QString(); - return d->executable->sourceURL(); + return d->fileName; } /*! @@ -164,7 +184,7 @@ int QScriptProgram::lineNumber() const Q_D(const QScriptProgram); if (!d) return -1; - return d->executable->lineNo(); + return d->lineNumber; } /*! @@ -173,6 +193,9 @@ int QScriptProgram::lineNumber() const */ bool QScriptProgram::operator==(const QScriptProgram &other) const { + Q_D(const QScriptProgram); + if (d == other.d_func()) + return true; return (sourceCode() == other.sourceCode()) && (fileName() == other.fileName()) && (lineNumber() == other.lineNumber()); diff --git a/src/script/api/qscriptprogram.h b/src/script/api/qscriptprogram.h index b6782b8..6ab56dc 100644 --- a/src/script/api/qscriptprogram.h +++ b/src/script/api/qscriptprogram.h @@ -44,6 +44,8 @@ #include +#include + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -55,12 +57,15 @@ class Q_SCRIPT_EXPORT QScriptProgram { public: QScriptProgram(); + QScriptProgram(const QString &sourceCode, + const QString fileName = QString(), + int lineNumber = 1); QScriptProgram(const QScriptProgram &other); ~QScriptProgram(); QScriptProgram &operator=(const QScriptProgram &other); - bool isValid() const; + bool isNull() const; QString sourceCode() const; QString fileName() const; diff --git a/src/script/api/qscriptprogram_p.h b/src/script/api/qscriptprogram_p.h index fe06b38..861ef32 100644 --- a/src/script/api/qscriptprogram_p.h +++ b/src/script/api/qscriptprogram_p.h @@ -58,6 +58,7 @@ namespace JSC { class EvalExecutable; + class ExecState; } QT_BEGIN_NAMESPACE @@ -67,20 +68,26 @@ class QScriptEnginePrivate; class QScriptProgramPrivate { public: - QScriptProgramPrivate(QScriptEnginePrivate*, - JSC::EvalExecutable*, - intptr_t); + QScriptProgramPrivate(const QString &sourceCode, + const QString &fileName, + int lineNumber); ~QScriptProgramPrivate(); static QScriptProgramPrivate *get(const QScriptProgram &q); - static QScriptProgram create(QScriptEnginePrivate*, - JSC::EvalExecutable*, - intptr_t); + + JSC::EvalExecutable *executable(JSC::ExecState *exec, + QScriptEnginePrivate *engine); QBasicAtomicInt ref; + + QString sourceCode; + QString fileName; + int lineNumber; + QScriptEnginePrivate *engine; - JSC::EvalExecutable *executable; + JSC::EvalExecutable *_executable; intptr_t sourceId; + bool isCompiled; }; QT_END_NAMESPACE diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index c00bde6..062cbfa 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -152,7 +152,7 @@ private slots: void installTranslatorFunctions(); void functionScopes(); void nativeFunctionScopes(); - void compileAndEvaluate(); + void evaluateProgram(); void qRegExpInport_data(); void qRegExpInport(); @@ -4291,7 +4291,7 @@ void tst_QScriptEngine::nativeFunctionScopes() } } -void tst_QScriptEngine::compileAndEvaluate() +void tst_QScriptEngine::evaluateProgram() { QScriptEngine eng; @@ -4299,21 +4299,23 @@ void tst_QScriptEngine::compileAndEvaluate() QString code("1 + 2"); QString fileName("hello.js"); int lineNumber(123); - QScriptProgram program = eng.compile(code, fileName, lineNumber); - QVERIFY(program.isValid()); + QScriptProgram program(code, fileName, lineNumber); + QVERIFY(!program.isNull()); QCOMPARE(program.sourceCode(), code); QCOMPARE(program.fileName(), fileName); QCOMPARE(program.lineNumber(), lineNumber); QScriptValue expected = eng.evaluate(code); - QScriptValue ret = eng.evaluate(program); - QVERIFY(ret.equals(expected)); + for (int x = 0; x < 10; ++x) { + QScriptValue ret = eng.evaluate(program); + QVERIFY(ret.equals(expected)); + } } // Program that accesses variable in the scope { - QScriptProgram program = eng.compile("a"); - QVERIFY(program.isValid()); + QScriptProgram program("a"); + QVERIFY(!program.isNull()); { QScriptValue ret = eng.evaluate(program); QVERIFY(ret.isError()); @@ -4350,8 +4352,8 @@ void tst_QScriptEngine::compileAndEvaluate() // Program that creates closure { - QScriptProgram program = eng.compile("(function() { var count = 0; return function() { return count++; }; })"); - QVERIFY(program.isValid()); + QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })"); + QVERIFY(!program.isNull()); QScriptValue createCounter = eng.evaluate(program); QVERIFY(createCounter.isFunction()); QScriptValue counter = createCounter.call(); @@ -4368,6 +4370,29 @@ void tst_QScriptEngine::compileAndEvaluate() QVERIFY(ret.isNumber()); } } + + // Same program run in different engines + { + QString code("1 + 2"); + QScriptProgram program(code); + QVERIFY(!program.isNull()); + double expected = eng.evaluate(program).toNumber(); + for (int x = 0; x < 2; ++x) { + QScriptEngine eng2; + for (int y = 0; y < 2; ++y) { + double ret = eng2.evaluate(program).toNumber(); + QCOMPARE(ret, expected); + } + } + } + + // No program + { + QScriptProgram program; + QVERIFY(program.isNull()); + QScriptValue ret = eng.evaluate(program); + QVERIFY(!ret.isValid()); + } } static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; } diff --git a/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp b/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp index 283e489..bdb0414 100644 --- a/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp +++ b/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp @@ -44,6 +44,7 @@ #include #include +#include #include //TESTED_CLASS= @@ -109,6 +110,9 @@ private slots: void extension_invoctaion(); void extension(); void isEvaluatingInExtension(); + void evaluateProgram(); + void evaluateProgram_SyntaxError(); + void evaluateNullProgram(); private: double m_testProperty; @@ -2182,5 +2186,88 @@ void tst_QScriptEngineAgent::isEvaluatingInExtension() QVERIFY(spy->wasEvaluating); } +void tst_QScriptEngineAgent::evaluateProgram() +{ + QScriptEngine eng; + QScriptProgram program("1 + 2", "foo.js", 123); + ScriptEngineSpy *spy = new ScriptEngineSpy(&eng); + qint64 scriptId = -1; + for (int x = 0; x < 10; ++x) { + spy->clear(); + (void)eng.evaluate(program); + QCOMPARE(spy->count(), (x == 0) ? 4 : 3); + + if (x == 0) { + // script is only loaded on first execution + QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad); + scriptId = spy->at(0).scriptId; + QVERIFY(scriptId != -1); + QCOMPARE(spy->at(0).script, program.sourceCode()); + QCOMPARE(spy->at(0).fileName, program.fileName()); + QCOMPARE(spy->at(0).lineNumber, program.lineNumber()); + spy->removeFirst(); + } + + QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry); // evaluate() + QCOMPARE(spy->at(0).scriptId, scriptId); + + QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); + QCOMPARE(spy->at(1).scriptId, scriptId); + QCOMPARE(spy->at(1).lineNumber, program.lineNumber()); + + QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit); // evaluate() + QCOMPARE(spy->at(2).scriptId, scriptId); + QVERIFY(spy->at(2).value.isNumber()); + QCOMPARE(spy->at(2).value.toNumber(), qsreal(3)); + } +} + +void tst_QScriptEngineAgent::evaluateProgram_SyntaxError() +{ + QScriptEngine eng; + QScriptProgram program("this is not valid syntax", "foo.js", 123); + ScriptEngineSpy *spy = new ScriptEngineSpy(&eng); + qint64 scriptId = -1; + for (int x = 0; x < 10; ++x) { + spy->clear(); + (void)eng.evaluate(program); + QCOMPARE(spy->count(), (x == 0) ? 8 : 7); + + if (x == 0) { + // script is only loaded on first execution + QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad); + scriptId = spy->at(0).scriptId; + QVERIFY(scriptId != -1); + QCOMPARE(spy->at(0).script, program.sourceCode()); + QCOMPARE(spy->at(0).fileName, program.fileName()); + QCOMPARE(spy->at(0).lineNumber, program.lineNumber()); + spy->removeFirst(); + } + + QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry); // evaluate() + QCOMPARE(spy->at(0).scriptId, scriptId); + + QCOMPARE(spy->at(1).type, ScriptEngineEvent::ContextPush); // SyntaxError constructor + QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionEntry); // SyntaxError constructor + QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit); // SyntaxError constructor + QCOMPARE(spy->at(4).type, ScriptEngineEvent::ContextPop); // SyntaxError constructor + + QCOMPARE(spy->at(5).type, ScriptEngineEvent::ExceptionThrow); + QVERIFY(spy->at(5).value.isError()); + QCOMPARE(spy->at(5).value.toString(), QString::fromLatin1("SyntaxError: Parse error")); + + QCOMPARE(spy->at(6).type, ScriptEngineEvent::FunctionExit); // evaluate() + QCOMPARE(spy->at(6).scriptId, scriptId); + } +} + +void tst_QScriptEngineAgent::evaluateNullProgram() +{ + QScriptEngine eng; + ScriptEngineSpy *spy = new ScriptEngineSpy(&eng); + (void)eng.evaluate(QScriptProgram()); + QCOMPARE(spy->count(), 0); +} + QTEST_MAIN(tst_QScriptEngineAgent) #include "tst_qscriptengineagent.moc" -- cgit v0.12 From 6cd67bb07271950cca86dcad764b8581da588a51 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Oct 2009 15:14:41 +0200 Subject: add benchmark for QScriptEngine::evaluate(QScriptProgram) --- tests/benchmarks/qscriptengine/tst_qscriptengine.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp b/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp index 4f011c4..8d5f6e6 100644 --- a/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp +++ b/tests/benchmarks/qscriptengine/tst_qscriptengine.cpp @@ -60,6 +60,8 @@ private slots: void constructor(); void evaluate_data(); void evaluate(); + void evaluateProgram_data(); + void evaluateProgram(); void connectAndDisconnect(); void newObject(); void newQObject(); @@ -153,6 +155,22 @@ void tst_QScriptEngine::connectAndDisconnect() } } +void tst_QScriptEngine::evaluateProgram_data() +{ + evaluate_data(); +} + +void tst_QScriptEngine::evaluateProgram() +{ + QFETCH(QString, code); + QScriptEngine engine; + QScriptProgram program(code); + + QBENCHMARK { + (void)engine.evaluate(program); + } +} + void tst_QScriptEngine::newObject() { QScriptEngine engine; @@ -241,6 +259,5 @@ void tst_QScriptEngine::nativeCall() } } - QTEST_MAIN(tst_QScriptEngine) #include "tst_qscriptengine.moc" -- cgit v0.12