diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/scripttools/debugging/qscriptdebuggerbackend.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/scripttools/debugging/qscriptdebuggerbackend.cpp')
-rw-r--r-- | src/scripttools/debugging/qscriptdebuggerbackend.cpp | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/src/scripttools/debugging/qscriptdebuggerbackend.cpp b/src/scripttools/debugging/qscriptdebuggerbackend.cpp new file mode 100644 index 0000000..24a3847 --- /dev/null +++ b/src/scripttools/debugging/qscriptdebuggerbackend.cpp @@ -0,0 +1,998 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtSCriptTools 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscriptdebuggerbackend_p.h" +#include "qscriptdebuggerbackend_p_p.h" +#include "qscriptdebuggeragent_p.h" +#include "qscriptdebuggercommandexecutor_p.h" +#include "qscriptdebuggerevent_p.h" +#include "qscriptdebuggervalue_p.h" +#include "qscriptscriptdata_p.h" +#include "qscriptbreakpointdata_p.h" +#include "qscriptobjectsnapshot_p.h" + +#include <QtScript/qscriptengine.h> +#include <QtScript/qscriptcontextinfo.h> +#include <QtScript/qscriptvalueiterator.h> + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QScriptDebuggerValue) +Q_DECLARE_METATYPE(QScriptDebuggerBackendPrivate*) + +QT_BEGIN_NAMESPACE + +/*! + \since 4.5 + \class QScriptDebuggerBackend + \internal + + \brief The QScriptDebuggerBackend class is the base class of debugger back-ends. + + QScriptDebuggerBackend builds on the QScriptDebuggerAgent class. + + This class is usually used together with the QScriptDebuggerFrontend + class, in order to form a (front-end, back-end) pair. + + Call attachTo() to attach to a QScriptEngine object. Call detach() + to detach from the current engine. + + Call stepInto() to step into the next script statement; call stepOver() + to step over the next script statement; and call stepOut() to step out + of the currently executing script function. An event() will be generated + when the stepping is completed. + + Call runToLocation() to execute script statements until a certain + location has been reached. An event() will be generated when the location + has been reached. + + Call interruptEvaluation() to request that evaluation should be + interrupted. An event() will be generated upon the next script + statement that is reached. + + Call continueEvalution() to allow script evaluation to continue. + + Call setBreakpoint() to set a breakpoint. A breakpoint event() will + be generated when a breakpoint is hit. Call deleteBreakpoint() to + delete a breakpoint. Call modifyBreakpoint() to change the state of + an existing breakpoint. + + Call contextCount() to obtain the number of active contexts + (frames). Call context() to obtain a pointer to a QScriptContext. + + \section1 Subclassing + + When subclassing QScriptDebuggerBackend, you must implement the pure + virtual event() function. This function typically forwards the event + to a QScriptDebuggerFrontend object. For most type of events, + event() should block until the back-end is instructed to resume + execution (e.g. until continueEvalution() is called). You must + implement resume(), which is responsible for making event() return. + + \sa QScriptDebuggerFrontend, QScriptDebuggerEvent +*/ + +// helper class that's used to handle our custom Qt events +class QScriptDebuggerBackendEventReceiver : public QObject +{ +public: + QScriptDebuggerBackendEventReceiver(QScriptDebuggerBackendPrivate *backend, + QObject *parent = 0) + : QObject(parent), m_backend(backend) {} + ~QScriptDebuggerBackendEventReceiver() {} + + bool event(QEvent *e) + { + return m_backend->event(e); + } + +private: + QScriptDebuggerBackendPrivate *m_backend; +}; + + +QScriptDebuggerBackendPrivate::QScriptDebuggerBackendPrivate() +{ + eventReceiver = 0; + agent = 0; + commandExecutor = 0; + pendingEvaluateLineNumber = -1; + ignoreExceptions = false; + nextScriptValueIteratorId = 0; + nextScriptObjectSnapshotId = 0; +} + +QScriptDebuggerBackendPrivate::~QScriptDebuggerBackendPrivate() +{ + if (agent) + agent->nullifyBackendPointer(); + delete commandExecutor; + delete eventReceiver; + qDeleteAll(scriptValueIterators); + qDeleteAll(scriptObjectSnapshots); +} + +void QScriptDebuggerBackendPrivate::postEvent(QEvent *e) +{ + if (!eventReceiver) { + eventReceiver = new QScriptDebuggerBackendEventReceiver(this); + eventReceiver->moveToThread(agent->engine()->thread()); + } + QCoreApplication::postEvent(eventReceiver, e); +} + +bool QScriptDebuggerBackendPrivate::event(QEvent *e) +{ + if (e->type() == QEvent::User+1) { + QScriptDebuggerEventEvent *de = static_cast<QScriptDebuggerEventEvent*>(e); + q_func()->event(de->event()); + return true; + } + return false; +} + +void QScriptDebuggerBackendPrivate::agentDestroyed(QScriptDebuggerAgent *ag) +{ + // Since agents are owned by the script engine, this in practice means + // that the engine has been destroyed. Invalidate our pointer so we + // don't crash later. + if (agent == ag) + agent = 0; +} + +/*! + The agent calls this function when it has completed a step + operation. +*/ +void QScriptDebuggerBackendPrivate::stepped(qint64 scriptId, + int lineNumber, + int columnNumber, + const QScriptValue &result) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::SteppingFinished, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + QScriptDebuggerValue value(result); + e.setScriptValue(value); + if (!result.isUndefined()) + e.setMessage(result.toString()); // for convenience -- we always need it + q->event(e); +} + +/*! + The agent calls this function when it has run to a particular + location. +*/ +void QScriptDebuggerBackendPrivate::locationReached(qint64 scriptId, + int lineNumber, + int columnNumber) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::LocationReached, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + q->event(e); +} + +/*! + The agent calls this function when evaluation has been interrupted. +*/ +void QScriptDebuggerBackendPrivate::interrupted(qint64 scriptId, + int lineNumber, + int columnNumber) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::Interrupted, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + q->event(e); +} + +/*! + The agent calls this function when a breakpoint has been triggered. +*/ +void QScriptDebuggerBackendPrivate::breakpoint(qint64 scriptId, + int lineNumber, + int columnNumber, + int breakpointId) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::Breakpoint, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + e.setBreakpointId(breakpointId); + q->event(e); +} + +/*! + The agent calls this function when an uncaught exception has + occurred. +*/ +void QScriptDebuggerBackendPrivate::exception(qint64 scriptId, + const QScriptValue &exception, + bool hasHandler) +{ + Q_Q(QScriptDebuggerBackend); + if (ignoreExceptions) { + // don't care (it's caught by us) + return; + } + QScriptDebuggerEvent e(QScriptDebuggerEvent::Exception); + e.setScriptId(scriptId); + e.setFileName(agent->scriptData(scriptId).fileName()); + e.setMessage(exception.toString()); + e.setHasExceptionHandler(hasHandler); + int lineNumber = -1; + QString fileName; + if (exception.property(QLatin1String("lineNumber")).isNumber()) + lineNumber = exception.property(QLatin1String("lineNumber")).toInt32(); + if (exception.property(QLatin1String("fileName")).isString()) + fileName = exception.property(QLatin1String("fileName")).toString(); + if (lineNumber == -1) { + QScriptContextInfo info(q->engine()->currentContext()); + lineNumber = info.lineNumber(); + fileName = info.fileName(); + } + if (lineNumber != -1) + e.setLineNumber(lineNumber); + if (!fileName.isEmpty()) + e.setFileName(fileName); + QScriptDebuggerValue value(exception); + e.setScriptValue(value); + q->event(e); +} + +QScriptValue QScriptDebuggerBackendPrivate::trace(QScriptContext *context, + QScriptEngine *engine) +{ + QScriptValue data = context->callee().data(); + QScriptDebuggerBackendPrivate *self = qscriptvalue_cast<QScriptDebuggerBackendPrivate*>(data); + if (!self) + return engine->undefinedValue(); + QString str; + for (int i = 0; i < context->argumentCount(); ++i) { + if (i > 0) + str.append(QLatin1String(" ")); + str.append(context->argument(i).toString()); + } + QScriptDebuggerEvent e(QScriptDebuggerEvent::Trace); + e.setMessage(str); + self->q_func()->event(e); + return engine->undefinedValue(); +} + +QScriptValue QScriptDebuggerBackendPrivate::qsassert(QScriptContext *context, + QScriptEngine *engine) +{ + QScriptValue arg = context->argument(0); + if (arg.toBoolean()) + return arg; + QScriptContextInfo info(context->parentContext()); + QString msg; + QString fileName = info.fileName(); + if (fileName.isEmpty()) + fileName = QString::fromLatin1("<anonymous script, id=%0>").arg(info.scriptId()); + msg.append(fileName); + msg.append(QLatin1Char(':')); + msg.append(QString::number(info.lineNumber())); + msg.append(QString::fromLatin1(": Assertion failed")); + for (int i = 1; i < context->argumentCount(); ++i) { + if (i == 1) + msg.append(QLatin1Char(':')); + msg.append(QLatin1Char(' ')); + msg.append(context->argument(i).toString()); + } + QScriptValue err = context->throwError(msg); + err.setProperty(QString::fromLatin1("name"), QScriptValue(engine, QString::fromLatin1("AssertionError"))); + return err; +} + +QScriptValue QScriptDebuggerBackendPrivate::fileName(QScriptContext *context, + QScriptEngine *engine) +{ + QScriptContextInfo info(context->parentContext()); + QString fn = info.fileName(); + if (fn.isEmpty()) + return engine->undefinedValue(); + return QScriptValue(engine, fn); +} + +QScriptValue QScriptDebuggerBackendPrivate::lineNumber(QScriptContext *context, + QScriptEngine *engine) +{ + QScriptContextInfo info(context->parentContext()); + return QScriptValue(engine, info.lineNumber()); +} + +/*! + The agent calls this function when the engine has reached a + "debugger" statement. +*/ +void QScriptDebuggerBackendPrivate::debuggerInvocationRequest( + qint64 scriptId, int lineNumber, int columnNumber) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::DebuggerInvocationRequest, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + q->event(e); +} + +void QScriptDebuggerBackendPrivate::forcedReturn( + qint64 scriptId, int lineNumber, int columnNumber, + const QScriptValue &value) +{ + Q_Q(QScriptDebuggerBackend); + QScriptDebuggerEvent e(QScriptDebuggerEvent::ForcedReturn, + scriptId, lineNumber, columnNumber); + e.setFileName(agent->scriptData(scriptId).fileName()); + e.setScriptValue(QScriptDebuggerValue(value)); + q->event(e); +} + +/*! + Creates a QScriptDebuggerBackend object. +*/ +QScriptDebuggerBackend::QScriptDebuggerBackend() + : d_ptr(new QScriptDebuggerBackendPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys this QScriptDebuggerBackend. +*/ +QScriptDebuggerBackend::~QScriptDebuggerBackend() +{ + detach(); + delete d_ptr; +} + +/*! + \internal +*/ +QScriptDebuggerBackend::QScriptDebuggerBackend(QScriptDebuggerBackendPrivate &dd) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; +} + +/*! + Attaches this backend to the given \a engine. + The backend automatically detaches from the old engine, if any. + + This function installs its own agent on the \a engine using + QScriptEngine::setAgent(); any existing agent will be replaced. + + \sa detach(). engine() +*/ +void QScriptDebuggerBackend::attachTo(QScriptEngine *engine) +{ + Q_D(QScriptDebuggerBackend); + detach(); + d->agent = new QScriptDebuggerAgent(d, engine); + QScriptValue global = engine->globalObject(); + global.setProperty(QString::fromLatin1("print"), traceFunction()); +// global.setProperty(QString::fromLatin1("qAssert"), assertFunction()); + global.setProperty(QString::fromLatin1("__FILE__"), fileNameFunction(), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter + | QScriptValue::ReadOnly); + global.setProperty(QString::fromLatin1("__LINE__"), lineNumberFunction(), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter + | QScriptValue::ReadOnly); + engine->setAgent(d->agent); +} + +/*! + Detaches this backend from the current script engine. + The backend's state (including breakpoints and information on loaded + scripts) will be invalidated. + + \sa attach() +*/ +void QScriptDebuggerBackend::detach() +{ + Q_D(QScriptDebuggerBackend); + if (!d->agent) + return; + QScriptEngine *eng = d->agent->engine(); + if (eng && eng->agent() == d->agent) { + eng->setAgent(0); + QScriptValue global = eng->globalObject(); + if (global.property(QString::fromLatin1("print")).strictlyEquals(traceFunction())) + global.setProperty(QString::fromLatin1("print"), QScriptValue()); +// global.setProperty(QString::fromLatin1("qAssert"), QScriptValue()); + if (global.property(QString::fromLatin1("__FILE__")).strictlyEquals(fileNameFunction())) + global.setProperty(QString::fromLatin1("__FILE__"), QScriptValue()); + if (global.property(QString::fromLatin1("__LINE__")).strictlyEquals(lineNumberFunction())) + global.setProperty(QString::fromLatin1("__LINE__"), QScriptValue()); + d->agent->nullifyBackendPointer(); + d->agent = 0; // agent is owned by engine + } + + d->pendingEvaluateLineNumber = -1; + d->ignoreExceptions = false; + d->nextScriptValueIteratorId = 0; + qDeleteAll(d->scriptValueIterators); + d->scriptValueIterators.clear(); + qDeleteAll(d->scriptObjectSnapshots); + d->scriptObjectSnapshots.clear(); +} + +/*! + Returns the script engine that this backend is attached to, or 0 if + the backend is not attached to an engine. + + \sa attachTo() +*/ +QScriptEngine *QScriptDebuggerBackend::engine() const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return 0; + return d->agent->engine(); +} + +/*! + Steps into the next script statement. + When stepping is complete, an event() will be generated. +*/ +void QScriptDebuggerBackend::stepInto(int count) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterStepIntoMode(count); + resume(); + } +} + +/*! + Steps over the next script statement. + When stepping is complete, an event() will be generated. +*/ +void QScriptDebuggerBackend::stepOver(int count) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterStepOverMode(count); + resume(); + } +} + +/*! + Steps out of the current script function. + When stepping is complete, an event() will be generated. +*/ +void QScriptDebuggerBackend::stepOut() +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterStepOutMode(); + resume(); + } +} + +/*! + Continues script evaluation. Evaluation will proceed without + interruption until either 1) an uncaught exception occurs, 2) a + breakpoint is triggered, or 3) interruptEvaluation() is called. + In each case, a proper event() will be generated. +*/ +void QScriptDebuggerBackend::continueEvalution() +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterContinueMode(); + resume(); + } +} + +/*! + Interrupts script evaluation. When the next script statement is + reached, an event() will be generated. +*/ +void QScriptDebuggerBackend::interruptEvaluation() +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) + d->agent->enterInterruptMode(); +} + +/*! + Continues evaluation until the location defined by the given \a + fileName and \a lineNumber is reached. When the location is reached, + an event() will be generated. +*/ +void QScriptDebuggerBackend::runToLocation(const QString &fileName, int lineNumber) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterRunToLocationMode(fileName, lineNumber); + resume(); + } +} + +/*! + Continues evaluation until the location defined by the given \a + scriptId and \a lineNumber is reached. When the location is reached, + an event() will be generated. +*/ +void QScriptDebuggerBackend::runToLocation(qint64 scriptId, int lineNumber) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterRunToLocationMode(scriptId, lineNumber); + resume(); + } +} + +void QScriptDebuggerBackend::returnToCaller(int contextIndex, const QScriptValue &value) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) { + d->agent->enterReturnByForceMode(contextIndex, value); + resume(); + } +} + +/*! + Evaluates the given \a program. When evaluation is complete, an + event() is generated. +*/ +void QScriptDebuggerBackend::evaluate(int contextIndex, const QString &program, + const QString &fileName, int lineNumber) +{ + Q_D(QScriptDebuggerBackend); + d->pendingEvaluateContextIndex = contextIndex; + d->pendingEvaluateProgram = program; + d->pendingEvaluateFileName = fileName; + d->pendingEvaluateLineNumber = lineNumber; + if (!engine()->isEvaluating()) + doPendingEvaluate(/*postEvent=*/true); + else + resume(); +} + +/*! + Executes the pending evaluate, if any. +*/ +void QScriptDebuggerBackend::doPendingEvaluate(bool postEvent) +{ + Q_D(QScriptDebuggerBackend); + QString program = d->pendingEvaluateProgram; + if (program.isEmpty()) + return; + int contextIndex = d->pendingEvaluateContextIndex; + QScriptContext *ctx = context(contextIndex); + Q_ASSERT(ctx != 0); + QString fileName = d->pendingEvaluateFileName; + int lineNumber = d->pendingEvaluateLineNumber; + d->pendingEvaluateProgram = QString(); + d->pendingEvaluateFileName = QString(); + d->pendingEvaluateLineNumber = -1; + d->pendingEvaluateContextIndex = -1; + + // push a new context and initialize its scope chain etc. + { + QScriptContext *evalContext = engine()->pushContext(); +#if QT_VERSION >= 0x040500 + QScriptValueList scopeChain = ctx->scopeChain(); + if (scopeChain.isEmpty()) + scopeChain.append(engine()->globalObject()); + while (!scopeChain.isEmpty()) + evalContext->pushScope(scopeChain.takeLast()); +#endif + evalContext->setActivationObject(ctx->activationObject()); + evalContext->setThisObject(ctx->thisObject()); + } + + d->agent->enterContinueMode(); + // set a flag so that any exception that happens in + // the evaluate() is not sent to the debugger + d->ignoreExceptions = true; + bool hadException = engine()->hasUncaughtException(); + QScriptValue ret = engine()->evaluate(program, fileName, lineNumber); + d->ignoreExceptions = false; + if (!hadException && engine()->hasUncaughtException()) + engine()->clearExceptions(); + engine()->popContext(); + + QScriptDebuggerValue retret(ret); + QScriptDebuggerEvent e(QScriptDebuggerEvent::InlineEvalFinished); + e.setScriptValue(retret); + if (!ret.isUndefined()) + e.setMessage(ret.toString()); // for convenience -- we always need it + + e.setNestedEvaluate(engine()->isEvaluating()); + + if (postEvent) { + QScriptDebuggerEventEvent *de = new QScriptDebuggerEventEvent(e); + d->postEvent(de); + } else { + event(e); + } +} + +/*! + Sets a breakpoint defined by the given \a data, and returns a unique + identifier for the new breakpoint. + + If the conditions of the breakpoint is satisfied at some point + during script evaluation, a breakpoint event() will be generated. + + \sa deleteBreakpoint(), breakpoints() +*/ +int QScriptDebuggerBackend::setBreakpoint(const QScriptBreakpointData &data) +{ + Q_D(QScriptDebuggerBackend); + if (!d->agent) + return -1; + if (!data.isValid()) + return -1; + return d->agent->setBreakpoint(data); +} + +/*! + Deletes the breakpoint identified by the given \a id. Returns true + if the breakpoint was deleted (i.e. the \a id was valid), otherwise + returns false. + + \sa setBreakpoint() +*/ +bool QScriptDebuggerBackend::deleteBreakpoint(int id) +{ + Q_D(QScriptDebuggerBackend); + if (!d->agent) + return false; + return d->agent->deleteBreakpoint(id); +} + +/*! + Deletes all breakpoints. +*/ +void QScriptDebuggerBackend::deleteAllBreakpoints() +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) + d->agent->deleteAllBreakpoints(); +} + +/*! + Returns the data associated with the breakpoint identified by the + given \a id. +*/ +QScriptBreakpointData QScriptDebuggerBackend::breakpointData(int id) const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QScriptBreakpointData(); + return d->agent->breakpointData(id); +} + +/*! + Sets the \a data associated with the breakpoint identified by the + given \a id. +*/ +bool QScriptDebuggerBackend::setBreakpointData(int id, const QScriptBreakpointData &data) +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) + return d->agent->setBreakpointData(id, data); + return false; +} + +/*! + Returns this backend's breakpoints. + + \sa setBreakpoint() +*/ +QScriptBreakpointMap QScriptDebuggerBackend::breakpoints() const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QScriptBreakpointMap(); + return d->agent->breakpoints(); +} + +/*! + Returns the scripts that this backend knows about. + + \sa scriptData() +*/ +QScriptScriptMap QScriptDebuggerBackend::scripts() const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QScriptScriptMap(); + return d->agent->scripts(); +} + +/*! + Returns the data for the script identified by the given \a id. + + \sa scripts() +*/ +QScriptScriptData QScriptDebuggerBackend::scriptData(qint64 id) const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QScriptScriptData(); + return d->agent->scriptData(id); +} + +/*! + Makes a checkpoint of the currently loaded scripts. + + \sa scriptsDelta() +*/ +void QScriptDebuggerBackend::scriptsCheckpoint() +{ + Q_D(QScriptDebuggerBackend); + if (d->agent) + d->agent->scriptsCheckpoint(); +} + +/*! + Returns the difference between the latest scripts checkpoint and the + previous checkpoint. The first item in the pair is a list + containing the identifiers of the scripts that were added. The + second item in the pair is a list containing the identifiers of the + scripts that were removed. + + \sa scriptsCheckpoint() +*/ +QScriptScriptsDelta QScriptDebuggerBackend::scriptsDelta() const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QPair<QList<qint64>, QList<qint64> >(); + return d->agent->scriptsDelta(); +} + +qint64 QScriptDebuggerBackend::resolveScript(const QString &fileName) const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return -1; + return d->agent->resolveScript(fileName); +} + +/*! + Returns the number of contexts (frames). +*/ +int QScriptDebuggerBackend::contextCount() const +{ + if (!engine()) + return 0; + int count = 0; + QScriptContext *ctx = engine()->currentContext(); + while (ctx) { + ++count; + ctx = ctx->parentContext(); + } + return count; +} + +/*! + Returns the context for the frame with the given \a index. +*/ +QScriptContext *QScriptDebuggerBackend::context(int index) const +{ + if (index < 0) + return 0; + QScriptContext *ctx = engine()->currentContext(); + while (ctx) { + if (index == 0) + return ctx; + ctx = ctx->parentContext(); + --index; + } + return 0; +} + +/*! + Returns a backtrace of the current execution. +*/ +QStringList QScriptDebuggerBackend::backtrace() const +{ + if (!engine()) + return QStringList(); + return engine()->currentContext()->backtrace(); +} + +QList<qint64> QScriptDebuggerBackend::contextIds() const +{ + Q_D(const QScriptDebuggerBackend); + if (!d->agent) + return QList<qint64>(); + return d->agent->contextIds(); +} + +QScriptContextsDelta QScriptDebuggerBackend::contextsCheckpoint() +{ + Q_D(QScriptDebuggerBackend); + if (!d->agent) + return QScriptContextsDelta(); + return d->agent->contextsCheckpoint(); +} + +int QScriptDebuggerBackend::newScriptObjectSnapshot() +{ + Q_D(QScriptDebuggerBackend); + int id = d->nextScriptObjectSnapshotId; + ++d->nextScriptObjectSnapshotId; + d->scriptObjectSnapshots[id] = new QScriptObjectSnapshot(); + return id; +} + +QScriptObjectSnapshot *QScriptDebuggerBackend::scriptObjectSnapshot(int id) const +{ + Q_D(const QScriptDebuggerBackend); + return d->scriptObjectSnapshots.value(id); +} + +void QScriptDebuggerBackend::deleteScriptObjectSnapshot(int id) +{ + Q_D(QScriptDebuggerBackend); + QScriptObjectSnapshot *snap = d->scriptObjectSnapshots.take(id); + delete snap; +} + +int QScriptDebuggerBackend::newScriptValueIterator(const QScriptValue &object) +{ + Q_D(QScriptDebuggerBackend); + int id = d->nextScriptValueIteratorId; + ++d->nextScriptValueIteratorId; + d->scriptValueIterators[id] = new QScriptValueIterator(object); + return id; +} + +QScriptValueIterator *QScriptDebuggerBackend::scriptValueIterator(int id) const +{ + Q_D(const QScriptDebuggerBackend); + return d->scriptValueIterators.value(id); +} + +void QScriptDebuggerBackend::deleteScriptValueIterator(int id) +{ + Q_D(QScriptDebuggerBackend); + QScriptValueIterator *it = d->scriptValueIterators.take(id); + delete it; +} + +bool QScriptDebuggerBackend::ignoreExceptions() const +{ + Q_D(const QScriptDebuggerBackend); + return d->ignoreExceptions; +} + +void QScriptDebuggerBackend::setIgnoreExceptions(bool ignore) +{ + Q_D(QScriptDebuggerBackend); + d->ignoreExceptions = ignore; +} + +/*! + Returns a trace function. The trace function has similar semantics + to the built-in print() function; however, instead of writing text + to standard output, it generates a trace event containing the text. +*/ +QScriptValue QScriptDebuggerBackend::traceFunction() const +{ + Q_D(const QScriptDebuggerBackend); + if (!engine()) + return QScriptValue(); + QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::trace); + fun.setData(qScriptValueFromValue(engine(), const_cast<QScriptDebuggerBackendPrivate*>(d))); + return fun; +} + +QScriptValue QScriptDebuggerBackend::assertFunction() const +{ + if (!engine()) + return QScriptValue(); + QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::qsassert); + return fun; +} + +QScriptValue QScriptDebuggerBackend::fileNameFunction() const +{ + if (!engine()) + return QScriptValue(); + QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::fileName); + return fun; +} + +QScriptValue QScriptDebuggerBackend::lineNumberFunction() const +{ + if (!engine()) + return QScriptValue(); + QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::lineNumber); + return fun; +} + +QScriptDebuggerCommandExecutor *QScriptDebuggerBackend::commandExecutor() const +{ + Q_D(const QScriptDebuggerBackend); + if (d->commandExecutor) + return d->commandExecutor; + QScriptDebuggerBackendPrivate *dd = const_cast<QScriptDebuggerBackendPrivate*>(d); + dd->commandExecutor = new QScriptDebuggerCommandExecutor(); + return dd->commandExecutor; +} + +void QScriptDebuggerBackend::setCommandExecutor(QScriptDebuggerCommandExecutor *executor) +{ + Q_D(QScriptDebuggerBackend); + d->commandExecutor = executor; +} + +/*! + \fn void QScriptDebuggerBackend::resume() + + This function is called when control should be returned back to the + back-end, i.e. when script evaluation should be resumed after an + event has been delivered. + + Subclasses must reimplement this function to make event() return. + + \sa event() +*/ + +/*! + \fn void QScriptDebuggerBackend::event(const QScriptDebuggerEvent &event) + + This function is called when the back-end has generated the given \a event. + + Subclasses must reimplement this function to handle the + event. Typically the event is forwarded to a + QScriptDebuggerFrontend, which will in turn forward it to its + QScriptDebuggerClient. The client may then query the front-end for + information about the execution state, and call e.g. + continueEvalution() to resume execution. This function should block + until resume() is called. + + \sa resume() +*/ + +QT_END_NAMESPACE |