summaryrefslogtreecommitdiff
path: root/src/scripttools/debugging/qscriptdebuggeragent.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commitc4af45c2914381172e1bd7ee528481edaa2fff1a (patch)
tree01265e109316fda93845e1c96c5e566d870f51d0 /src/scripttools/debugging/qscriptdebuggeragent.cpp
downloadqtscript-c4af45c2914381172e1bd7ee528481edaa2fff1a.tar.gz
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/scripttools/debugging/qscriptdebuggeragent.cpp')
-rw-r--r--src/scripttools/debugging/qscriptdebuggeragent.cpp730
1 files changed, 730 insertions, 0 deletions
diff --git a/src/scripttools/debugging/qscriptdebuggeragent.cpp b/src/scripttools/debugging/qscriptdebuggeragent.cpp
new file mode 100644
index 0000000..7aa0d85
--- /dev/null
+++ b/src/scripttools/debugging/qscriptdebuggeragent.cpp
@@ -0,0 +1,730 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 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 "qscriptdebuggeragent_p.h"
+#include "qscriptdebuggeragent_p_p.h"
+#include "qscriptdebuggerbackend_p_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qset.h>
+#include <QtScript/qscriptengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 4.5
+ \class QScriptDebuggerAgent
+ \internal
+
+ This class implements a state machine that uses the low-level events
+ reported by the QScriptEngineAgent interface to implement debugging-
+ specific functionality such as stepping and breakpoints. It is used
+ internally by the QScriptDebuggerBackend class.
+*/
+
+QScriptDebuggerAgentPrivate::QScriptDebuggerAgentPrivate()
+ : state(NoState), stepDepth(0), stepCount(0),
+ targetScriptId(-1), targetLineNumber(-1), returnCounter(0),
+ nextBreakpointId(1), hitBreakpointId(0),
+ nextContextId(0), statementCounter(0)
+{
+}
+
+QScriptDebuggerAgentPrivate::~QScriptDebuggerAgentPrivate()
+{
+}
+
+QScriptDebuggerAgentPrivate *QScriptDebuggerAgentPrivate::get(
+ QScriptDebuggerAgent *q)
+{
+ if (!q)
+ return 0;
+ return q->d_func();
+}
+
+
+/*!
+ Constructs a new agent for the given \a engine. The agent will
+ report debugging-related events (e.g. step completion) to the given
+ \a backend.
+*/
+QScriptDebuggerAgent::QScriptDebuggerAgent(
+ QScriptDebuggerBackendPrivate *backend, QScriptEngine *engine)
+ : QScriptEngineAgent(engine), d_ptr(new QScriptDebuggerAgentPrivate())
+{
+ Q_D(QScriptDebuggerAgent);
+ d->backend = backend;
+
+ QScriptContext *ctx = engine->currentContext();
+ while (ctx) {
+ d->scriptIdStack.append(QList<qint64>());
+ d->contextIdStack.append(d->nextContextId);
+ ++d->nextContextId;
+ ctx = ctx->parentContext();
+ }
+}
+
+/*!
+ Destroys this QScriptDebuggerAgent.
+*/
+QScriptDebuggerAgent::~QScriptDebuggerAgent()
+{
+ Q_D(QScriptDebuggerAgent);
+ if (d->backend)
+ d->backend->agentDestroyed(this);
+ delete d;
+}
+
+/*!
+ Instructs the agent to perform a "step into" operation. This
+ function returns immediately. The agent will report step completion
+ at a later time, i.e. when script statements are evaluated.
+*/
+void QScriptDebuggerAgent::enterStepIntoMode(int count)
+{
+ Q_D(QScriptDebuggerAgent);
+ d->state = QScriptDebuggerAgentPrivate::SteppingIntoState;
+ d->stepCount = count;
+ d->stepResult = QScriptValue();
+}
+
+/*!
+ Instructs the agent to perform a "step over" operation. This
+ function returns immediately. The agent will report step completion
+ at a later time, i.e. when script statements are evaluated.
+*/
+void QScriptDebuggerAgent::enterStepOverMode(int count)
+{
+ Q_D(QScriptDebuggerAgent);
+ d->state = QScriptDebuggerAgentPrivate::SteppingOverState;
+ if (engine()->isEvaluating())
+ d->stepDepth = 0;
+ else
+ d->stepDepth = -1;
+ d->stepCount = count;
+ d->stepResult = QScriptValue();
+}
+
+/*!
+ Instructs the agent to perform a "step out" operation. This
+ function returns immediately. The agent will report step completion
+ at a later time, i.e. when script statements are evaluated.
+*/
+void QScriptDebuggerAgent::enterStepOutMode()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->state = QScriptDebuggerAgentPrivate::SteppingOutState;
+ if (engine()->isEvaluating())
+ d->stepDepth = 0;
+ else
+ d->stepDepth = -1;
+}
+
+/*!
+ Instructs the agent to continue evaluation.
+ This function returns immediately.
+*/
+void QScriptDebuggerAgent::enterContinueMode()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+}
+
+/*!
+ Instructs the agent to interrupt evaluation.
+ This function returns immediately.
+*/
+void QScriptDebuggerAgent::enterInterruptMode()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->state = QScriptDebuggerAgentPrivate::InterruptingState;
+}
+
+/*!
+ Instructs the agent to continue evaluation until the location
+ described by \a fileName and \a lineNumber is reached. This
+ function returns immediately.
+*/
+void QScriptDebuggerAgent::enterRunToLocationMode(const QString &fileName, int lineNumber)
+{
+ Q_D(QScriptDebuggerAgent);
+ d->targetFileName = fileName;
+ d->targetLineNumber = lineNumber;
+ d->targetScriptId = resolveScript(fileName);
+ d->state = QScriptDebuggerAgentPrivate::RunningToLocationState;
+}
+
+/*!
+ Instructs the agent to continue evaluation until the location
+ described by \a scriptId and \a lineNumber is reached. This
+ function returns immediately.
+*/
+void QScriptDebuggerAgent::enterRunToLocationMode(qint64 scriptId, int lineNumber)
+{
+ Q_D(QScriptDebuggerAgent);
+ d->targetScriptId = scriptId;
+ d->targetFileName = QString();
+ d->targetLineNumber = lineNumber;
+ d->state = QScriptDebuggerAgentPrivate::RunningToLocationState;
+}
+
+void QScriptDebuggerAgent::enterReturnByForceMode(int contextIndex, const QScriptValue &value)
+{
+ Q_D(QScriptDebuggerAgent);
+ d->returnCounter = contextIndex + 1;
+ d->returnValue = QScriptValue();
+ d->state = QScriptDebuggerAgentPrivate::ReturningByForceState;
+ // throw an exception; we will catch it when the proper frame is popped
+ engine()->currentContext()->throwValue(value);
+}
+
+/*!
+ Sets a breakpoint defined by the given \a data.
+ Returns an integer that uniquely identifies the new breakpoint,
+ or -1 if setting the breakpoint failed.
+*/
+int QScriptDebuggerAgent::setBreakpoint(const QScriptBreakpointData &data)
+{
+ Q_D(QScriptDebuggerAgent);
+ qint64 scriptId = data.scriptId();
+ if (scriptId != -1) {
+ if (!d->scripts.contains(scriptId)) {
+ // that script has been unloaded, so invalidate the ID
+ scriptId = -1;
+ const_cast<QScriptBreakpointData&>(data).setScriptId(-1);
+ } else if (data.fileName().isEmpty()) {
+ QString fileName = d->scripts[scriptId].fileName();
+ const_cast<QScriptBreakpointData&>(data).setFileName(fileName);
+ }
+ }
+
+ int id = d->nextBreakpointId;
+ ++d->nextBreakpointId;
+
+ if (scriptId != -1) {
+ d->resolvedBreakpoints[scriptId].append(id);
+ } else {
+ QString fileName = data.fileName();
+ bool resolved = false;
+ QScriptScriptMap::const_iterator it;
+ for (it = d->scripts.constBegin(); it != d->scripts.constEnd(); ++it) {
+ if (it.value().fileName() == fileName) {
+ d->resolvedBreakpoints[it.key()].append(id);
+ resolved = true;
+ break;
+ }
+ }
+ if (!resolved)
+ d->unresolvedBreakpoints[fileName].append(id);
+ }
+
+ d->breakpoints.insert(id, data);
+
+ return id;
+}
+
+/*!
+ Deletes the breakpoint with the given \a id.
+ Returns true if the breakpoint was deleted, false if
+ no such breakpoint exists.
+*/
+bool QScriptDebuggerAgent::deleteBreakpoint(int id)
+{
+ Q_D(QScriptDebuggerAgent);
+ if (!d->breakpoints.contains(id))
+ return false;
+ d->breakpoints.remove(id);
+ bool found = false;
+ {
+ QHash<qint64, QList<int> >::iterator it;
+ it = d->resolvedBreakpoints.begin();
+ for ( ; !found && (it != d->resolvedBreakpoints.end()); ) {
+ QList<int> &lst = it.value();
+ Q_ASSERT(!lst.isEmpty());
+ for (int i = 0; i < lst.size(); ++i) {
+ if (lst.at(i) == id) {
+ lst.removeAt(i);
+ found = true;
+ break;
+ }
+ }
+ if (lst.isEmpty())
+ it = d->resolvedBreakpoints.erase(it);
+ else
+ ++it;
+ }
+ }
+ if (!found) {
+ QHash<QString, QList<int> >::iterator it;
+ it = d->unresolvedBreakpoints.begin();
+ for ( ; !found && (it != d->unresolvedBreakpoints.end()); ) {
+ QList<int> &lst = it.value();
+ Q_ASSERT(!lst.isEmpty());
+ for (int i = 0; i < lst.size(); ++i) {
+ if (lst.at(i) == id) {
+ lst.removeAt(i);
+ found = true;
+ break;
+ }
+ }
+ if (lst.isEmpty())
+ it = d->unresolvedBreakpoints.erase(it);
+ else
+ ++it;
+ }
+ }
+ return found;
+}
+
+/*!
+ Deletes all breakpoints.
+*/
+void QScriptDebuggerAgent::deleteAllBreakpoints()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->breakpoints.clear();
+ d->resolvedBreakpoints.clear();
+ d->unresolvedBreakpoints.clear();
+}
+
+/*!
+ Returns the data associated with the breakpoint with the given \a
+ id.
+*/
+QScriptBreakpointData QScriptDebuggerAgent::breakpointData(int id) const
+{
+ Q_D(const QScriptDebuggerAgent);
+ return d->breakpoints.value(id);
+}
+
+/*!
+ Sets the data associated with the breakpoint with the given \a
+ id.
+*/
+bool QScriptDebuggerAgent::setBreakpointData(int id,
+ const QScriptBreakpointData &data)
+{
+ Q_D(QScriptDebuggerAgent);
+ if (!d->breakpoints.contains(id))
+ return false;
+ d->breakpoints[id] = data;
+ return true;
+}
+
+/*!
+ Returns all breakpoints.
+*/
+QScriptBreakpointMap QScriptDebuggerAgent::breakpoints() const
+{
+ Q_D(const QScriptDebuggerAgent);
+ return d->breakpoints;
+}
+
+/*!
+ Returns all scripts.
+*/
+QScriptScriptMap QScriptDebuggerAgent::scripts() const
+{
+ Q_D(const QScriptDebuggerAgent);
+ return d->scripts;
+}
+
+/*!
+ Returns the data associated with the script with the given \a id.
+*/
+QScriptScriptData QScriptDebuggerAgent::scriptData(qint64 id) const
+{
+ Q_D(const QScriptDebuggerAgent);
+ return d->scripts.value(id);
+}
+
+/*!
+ Checkpoints the current scripts.
+*/
+void QScriptDebuggerAgent::scriptsCheckpoint()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->previousCheckpointScripts = d->checkpointScripts;
+ d->checkpointScripts = d->scripts;
+}
+
+/*!
+ Returns the difference between the current 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.
+*/
+QPair<QList<qint64>, QList<qint64> > QScriptDebuggerAgent::scriptsDelta() const
+{
+ Q_D(const QScriptDebuggerAgent);
+ QSet<qint64> prevSet = d->previousCheckpointScripts.keys().toSet();
+ QSet<qint64> currSet = d->checkpointScripts.keys().toSet();
+ QSet<qint64> addedScriptIds = currSet - prevSet;
+ QSet<qint64> removedScriptIds = prevSet - currSet;
+ return qMakePair(addedScriptIds.toList(), removedScriptIds.toList());
+}
+
+/*!
+ Returns the identifier of the script that has the given \a fileName,
+ or -1 if there is no such script.
+*/
+qint64 QScriptDebuggerAgent::resolveScript(const QString &fileName) const
+{
+ Q_D(const QScriptDebuggerAgent);
+ QScriptScriptMap::const_iterator it;
+ for (it = d->scripts.constBegin(); it != d->scripts.constEnd(); ++it) {
+ if (it.value().fileName() == fileName)
+ return it.key();
+ }
+ return -1;
+}
+
+QList<qint64> QScriptDebuggerAgent::contextIds() const
+{
+ Q_D(const QScriptDebuggerAgent);
+ return d->contextIdStack;
+}
+
+QPair<QList<qint64>, QList<qint64> > QScriptDebuggerAgent::contextsCheckpoint()
+{
+ Q_D(QScriptDebuggerAgent);
+ int i = d->checkpointContextIdStack.size() - 1;
+ int j = d->contextIdStack.size() - 1;
+ for ( ; (i >= 0) && (j >= 0); --i, --j) {
+ if (d->checkpointContextIdStack.at(i) != d->contextIdStack.at(j))
+ break;
+ }
+ QList<qint64> removed = d->checkpointContextIdStack.mid(0, i+1);
+ QList<qint64> added = d->contextIdStack.mid(0, j+1);
+ d->checkpointContextIdStack = d->contextIdStack;
+ return qMakePair(removed, added);
+}
+
+void QScriptDebuggerAgent::nullifyBackendPointer()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->backend = 0;
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::scriptLoad(qint64 id, const QString &program,
+ const QString &fileName, int baseLineNumber)
+{
+ Q_D(QScriptDebuggerAgent);
+ QScriptScriptData data = QScriptScriptData(program, fileName, baseLineNumber);
+ d->scripts.insert(id, data);
+
+ if ((d->state == QScriptDebuggerAgentPrivate::RunningToLocationState)
+ && (d->targetScriptId == -1)
+ && ((d->targetFileName == fileName) || d->targetFileName.isEmpty())) {
+ d->targetScriptId = id;
+ }
+
+ if (!fileName.isEmpty()) {
+ QList<int> lst = d->unresolvedBreakpoints.take(fileName);
+ if (!lst.isEmpty())
+ d->resolvedBreakpoints.insert(id, lst);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::scriptUnload(qint64 id)
+{
+ Q_D(QScriptDebuggerAgent);
+ QScriptScriptData data = d->scripts.take(id);
+ QString fileName = data.fileName();
+
+ if ((d->state == QScriptDebuggerAgentPrivate::RunningToLocationState)
+ && (d->targetScriptId == id)) {
+ d->targetScriptId = -1;
+ d->targetFileName = fileName;
+ }
+
+ if (!fileName.isEmpty()) {
+ QList<int> lst = d->resolvedBreakpoints.take(id);
+ if (!lst.isEmpty())
+ d->unresolvedBreakpoints.insert(fileName, lst);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::contextPush()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->scriptIdStack.append(QList<qint64>());
+ d->contextIdStack.prepend(d->nextContextId);
+ ++d->nextContextId;
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::contextPop()
+{
+ Q_D(QScriptDebuggerAgent);
+ d->scriptIdStack.removeLast();
+ d->contextIdStack.removeFirst();
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::functionEntry(qint64 scriptId)
+{
+ Q_D(QScriptDebuggerAgent);
+ QList<qint64> &ids = d->scriptIdStack.last();
+ ids.append(scriptId);
+ if ((d->state == QScriptDebuggerAgentPrivate::SteppingOverState)
+ || (d->state == QScriptDebuggerAgentPrivate::SteppingOutState)) {
+ ++d->stepDepth;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::functionExit(qint64 scriptId,
+ const QScriptValue &returnValue)
+{
+ Q_UNUSED(scriptId);
+ Q_D(QScriptDebuggerAgent);
+ QList<qint64> &ids = d->scriptIdStack.last();
+ ids.removeLast();
+ if (d->state == QScriptDebuggerAgentPrivate::SteppingOverState) {
+ --d->stepDepth;
+ } else if (d->state == QScriptDebuggerAgentPrivate::SteppingOutState) {
+ if (--d->stepDepth < 0) {
+ d->stepResult = returnValue;
+ d->state = QScriptDebuggerAgentPrivate::SteppedOutState;
+ }
+ } else if (d->state == QScriptDebuggerAgentPrivate::ReturningByForceState) {
+ if (--d->returnCounter == 0) {
+ d->returnValue = returnValue;
+ d->state = QScriptDebuggerAgentPrivate::ReturnedByForceState;
+ engine()->clearExceptions();
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::positionChange(qint64 scriptId,
+ int lineNumber, int columnNumber)
+{
+ Q_D(QScriptDebuggerAgent);
+ if (engine()->processEventsInterval() == -1) {
+ // see if it's time to call processEvents()
+ if ((++d->statementCounter % 25000) == 0) {
+ if (!d->processEventsTimer.isNull()) {
+ if (d->processEventsTimer.elapsed() > 30) {
+ QCoreApplication::processEvents();
+ d->processEventsTimer.restart();
+ }
+ } else {
+ d->processEventsTimer.start();
+ }
+ }
+ }
+
+ // check breakpoints
+ {
+ QList<int> lst = d->resolvedBreakpoints.value(scriptId);
+ for (int i = 0; i < lst.size(); ++i) {
+ int id = lst.at(i);
+ QScriptBreakpointData &data = d->breakpoints[id];
+ if (!data.isEnabled())
+ continue;
+ if (data.lineNumber() != lineNumber)
+ continue;
+ if (!data.condition().isEmpty()) {
+ // ### careful, evaluate() can cause an exception
+ // ### disable callbacks in nested evaluate?
+ QScriptDebuggerAgentPrivate::State was = d->state;
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ QScriptValue ret = engine()->evaluate(
+ data.condition(),
+ QString::fromLatin1("Breakpoint %0 condition checker").arg(id));
+ if (!ret.isError())
+ d->state = was;
+ if (!ret.toBoolean())
+ continue;
+ }
+ if (!data.hit())
+ continue;
+ d->hitBreakpointId = id;
+ d->state = QScriptDebuggerAgentPrivate::BreakpointState;
+ }
+ }
+
+ switch (d->state) {
+ case QScriptDebuggerAgentPrivate::NoState:
+ case QScriptDebuggerAgentPrivate::SteppingOutState:
+ case QScriptDebuggerAgentPrivate::ReturningByForceState:
+ // Do nothing
+ break;
+
+ case QScriptDebuggerAgentPrivate::SteppingIntoState:
+ if (--d->stepCount == 0) {
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->stepped(scriptId, lineNumber, columnNumber, QScriptValue());
+ }
+ break;
+
+ case QScriptDebuggerAgentPrivate::SteppingOverState:
+ if ((d->stepDepth > 0) || (--d->stepCount != 0))
+ break;
+ // fallthrough
+ case QScriptDebuggerAgentPrivate::SteppedOverState:
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->stepped(scriptId, lineNumber, columnNumber, d->stepResult);
+ break;
+
+ case QScriptDebuggerAgentPrivate::SteppedOutState:
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->stepped(scriptId, lineNumber, columnNumber, d->stepResult);
+ break;
+
+ case QScriptDebuggerAgentPrivate::RunningToLocationState:
+ if (((lineNumber == d->targetLineNumber) || (d->targetLineNumber == -1))
+ && (scriptId == d->targetScriptId)) {
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->locationReached(scriptId, lineNumber, columnNumber);
+ }
+ break;
+
+ case QScriptDebuggerAgentPrivate::InterruptingState:
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->interrupted(scriptId, lineNumber, columnNumber);
+ break;
+
+ case QScriptDebuggerAgentPrivate::BreakpointState:
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->breakpoint(scriptId, lineNumber, columnNumber, d->hitBreakpointId);
+ if (d->breakpoints.value(d->hitBreakpointId).isSingleShot())
+ deleteBreakpoint(d->hitBreakpointId);
+ break;
+
+ case QScriptDebuggerAgentPrivate::ReturnedByForceState:
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend)
+ d->backend->forcedReturn(scriptId, lineNumber, columnNumber, d->returnValue);
+ break;
+
+ case QScriptDebuggerAgentPrivate::SteppedIntoState:
+ case QScriptDebuggerAgentPrivate::ReachedLocationState:
+ case QScriptDebuggerAgentPrivate::InterruptedState:
+// ### deal with the case when code is evaluated while we're already paused
+// Q_ASSERT(false);
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::exceptionThrow(qint64 scriptId,
+ const QScriptValue &exception,
+ bool hasHandler)
+{
+ Q_D(QScriptDebuggerAgent);
+ if (d->state == QScriptDebuggerAgentPrivate::ReturningByForceState) {
+ // we threw this exception ourselves, so ignore it for now
+ // (see functionExit()).
+ return;
+ }
+ if (d->backend)
+ d->backend->exception(scriptId, exception, hasHandler);
+}
+
+/*!
+ \reimp
+*/
+void QScriptDebuggerAgent::exceptionCatch(qint64 scriptId,
+ const QScriptValue &exception)
+{
+ Q_UNUSED(scriptId);
+ Q_UNUSED(exception);
+}
+
+/*!
+ \reimp
+*/
+bool QScriptDebuggerAgent::supportsExtension(Extension extension) const
+{
+ return (extension == DebuggerInvocationRequest);
+}
+
+/*!
+ \reimp
+*/
+QVariant QScriptDebuggerAgent::extension(Extension extension,
+ const QVariant &argument)
+{
+ Q_UNUSED(extension);
+ Q_D(QScriptDebuggerAgent);
+ Q_ASSERT(extension == DebuggerInvocationRequest);
+ QVariantList lst = argument.toList();
+ qint64 scriptId = lst.at(0).toLongLong();
+ int lineNumber = lst.at(1).toInt();
+ int columnNumber = lst.at(2).toInt();
+ d->state = QScriptDebuggerAgentPrivate::NoState;
+ if (d->backend) {
+ d->backend->debuggerInvocationRequest(
+ scriptId, lineNumber, columnNumber);
+ }
+ return QVariant();
+}
+
+QT_END_NAMESPACE