From f9f878ca1fff08b6ea24507a84adfeb16d8938b6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 28 Sep 2009 18:51:54 +1000 Subject: Add two step compile/evaluate support to QScript --- src/script/api/qscriptengine.cpp | 173 +++++++++++++++++++++++++++++++++++++++ src/script/api/qscriptengine.h | 26 ++++++ 2 files changed, 199 insertions(+) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index fb14940..7256f27 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -340,6 +340,24 @@ public: JSC::JSValue prototype; }; +class QScriptProgramPrivate +{ +public: + QScriptProgramPrivate() : refcount(1), hasException(false) { } + + void addref() { ++refcount; } + void release() { if (--refcount) delete this; } + + int refcount; + + bool hasException; + QScriptValue exception; + + JSC::SourceCode source; + WTF::RefPtr evalNode; +}; + + namespace QScript { @@ -2114,7 +2132,112 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra return QScriptSyntaxCheckResult(p); } +QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) +{ + Q_D(QScriptEngine); + + QScriptProgram rv; + rv.d = new QScriptProgramPrivate; + + 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; + + JSC::SourceCode &source = rv.d->source; + source = JSC::makeSource(jscProgram, jscFileName, lineNumber); + + intptr_t sourceId = source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + int errorLine; + JSC::UString errorMessage; + WTF::RefPtr &evalNode = rv.d->evalNode; + evalNode = exec->globalData().parser->parse(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage); + if (!evalNode) { + JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0); + exec->setException(exceptionValue); + + if (debugger) { + debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, exceptionValue), sourceId, false); + debugger->evaluateStop(exceptionValue, sourceId); + } + + rv.d->hasException = true; + rv.d->exception = d->scriptValueFromJSCValue(exceptionValue); + } else if (debugger) { + debugger->evaluateStop(JSC::JSValue(), sourceId); + } + + return rv; +} + +QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) +{ + Q_D(QScriptEngine); + + if (0 == program.d) + return QScriptValue(); + else if (program.d->hasException) + return program.d->exception; + else if (!program.d->evalNode) + return QScriptValue(); + + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::ExecState* exec = d->currentFrame; + + intptr_t sourceId = program.d->source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + WTF::RefPtr &evalNode = program.d->evalNode; + + JSC::JSValue thisValue = d->thisForContext(exec); + JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + JSC::JSValue exceptionValue; + d->timeoutChecker()->setShouldAbort(false); + JSC::JSValue result = exec->interpreter()->execute(evalNode.get(), 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); +} /*! Evaluates \a program, using \a lineNumber as the base line number, @@ -3708,6 +3831,9 @@ QScriptValue QScriptEngine::objectById(qint64 id) const return const_cast(d)->scriptValueFromJSCValue((JSC::JSCell*)id); } + + + /*! \since 4.5 \class QScriptSyntaxCheckResult @@ -3836,4 +3962,51 @@ Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled() } #endif +QScriptProgram::QScriptProgram() +: d(0) +{ +} + +QScriptProgram::~QScriptProgram() +{ + if (d) d->release(); +} + +QScriptProgram::QScriptProgram(const QScriptProgram &c) +: d(c.d) +{ + if (d) d->addref(); +} + +QScriptProgram &QScriptProgram::operator=(const QScriptProgram &c) +{ + if (c.d) c.d->addref(); + if (d) d->release(); + d = c.d; + return *this; +} + +bool QScriptProgram::isNull() const +{ + return d == 0; +} + +bool QScriptProgram::hasSyntaxError() const +{ + if (d) return d->hasException; + else return false; +} + +QScriptValue QScriptProgram::syntaxError() const +{ + if (d) return d->exception; + else return QScriptValue(); +} + +QString QScriptProgram::programSource() const +{ + if (d) return d->source.toString(); + else return QString(); +} + QT_END_NAMESPACE diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index 701f9c6..71266cc 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -120,6 +120,29 @@ private: friend class QScriptEnginePrivate; }; +class QScriptProgramPrivate; +class Q_SCRIPT_EXPORT QScriptProgram +{ +public: + QScriptProgram(); + QScriptProgram(const QScriptProgram &); + ~QScriptProgram(); + + QScriptProgram &operator=(const QScriptProgram &); + + bool isNull() const; + + bool hasSyntaxError() const; + QScriptValue syntaxError() const; + + QString programSource() const; + +private: + friend class QScriptEngine; + QScriptProgramPrivate *d; +}; + +class QScriptCode; class Q_SCRIPT_EXPORT QScriptEngine #ifndef QT_NO_QOBJECT : public QObject @@ -164,6 +187,9 @@ public: bool canEvaluate(const QString &program) const; static QScriptSyntaxCheckResult checkSyntax(const QString &program); + QScriptProgram compile(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QScriptValue evaluate(const QScriptProgram &); + QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); bool isEvaluating() const; -- cgit v0.12