Files correlati : cg0.exe cg0700a.msk cg0700b.msk cg3.exe cg4.exe Bug : Commento: Merge 1.0 libraries
737 lines
22 KiB
C++
737 lines
22 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the examples of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:BSD$
|
|
** You may use this file under the terms of the BSD license as follows:
|
|
**
|
|
** "Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions are
|
|
** met:
|
|
** * Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** * Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in
|
|
** the documentation and/or other materials provided with the
|
|
** distribution.
|
|
** * Neither the name of The Qt Company Ltd nor the names of its
|
|
** contributors may be used to endorse or promote products derived
|
|
** from this software without specific prior written permission.
|
|
**
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "scriptdebugger.h"
|
|
#include "scriptbreakpointmanager.h"
|
|
|
|
#include <QtScript/QScriptEngine>
|
|
#include <QtScript/QScriptEngineAgent>
|
|
#include <QtScript/QScriptContextInfo>
|
|
#include <QtScript/QScriptValueIterator>
|
|
#include <QtCore/QTextStream>
|
|
#include <QtCore/QStack>
|
|
|
|
static QString safeValueToString(const QScriptValue &value)
|
|
{
|
|
if (value.isObject())
|
|
return QLatin1String("[object Object]");
|
|
else
|
|
return value.toString();
|
|
}
|
|
|
|
class ScriptInfo;
|
|
class ScriptBreakpointManager;
|
|
|
|
class ScriptDebuggerPrivate
|
|
: public QScriptEngineAgent
|
|
{
|
|
Q_DECLARE_PUBLIC(ScriptDebugger)
|
|
public:
|
|
enum Mode {
|
|
Run,
|
|
StepInto,
|
|
StepOver
|
|
};
|
|
|
|
ScriptDebuggerPrivate(QScriptEngine *engine);
|
|
~ScriptDebuggerPrivate();
|
|
|
|
// QScriptEngineAgent interface
|
|
void scriptLoad(qint64 id, const QString &program,
|
|
const QString &fileName, int lineNumber);
|
|
void scriptUnload(qint64 id);
|
|
|
|
void positionChange(qint64 scriptId,
|
|
int lineNumber, int columnNumber);
|
|
|
|
void functionEntry(qint64 scriptId);
|
|
void functionExit(qint64 scriptId,
|
|
const QScriptValue &returnValue);
|
|
|
|
void exceptionThrow(qint64 scriptId,
|
|
const QScriptValue &exception, bool hasHandler);
|
|
|
|
|
|
void interactive();
|
|
bool executeCommand(const QString &command, const QStringList &args);
|
|
|
|
void setMode(Mode mode);
|
|
Mode mode() const;
|
|
|
|
int frameCount() const;
|
|
void setCurrentFrameIndex(int index);
|
|
int currentFrameIndex() const;
|
|
|
|
QScriptContext *frameContext(int index) const;
|
|
QScriptContext *currentFrameContext() const;
|
|
|
|
ScriptInfo *scriptInfo(QScriptContext *context) const;
|
|
|
|
int listLineNumber() const;
|
|
void setListLineNumber(int lineNumber);
|
|
|
|
QString readLine();
|
|
void output(const QString &text);
|
|
void message(const QString &text);
|
|
void errorMessage(const QString &text);
|
|
|
|
// attributes
|
|
QTextStream *m_defaultInputStream;
|
|
QTextStream *m_defaultOutputStream;
|
|
QTextStream *m_defaultErrorStream;
|
|
QTextStream *m_inputStream;
|
|
QTextStream *m_outputStream;
|
|
QTextStream *m_errorStream;
|
|
|
|
ScriptBreakpointManager *m_bpManager;
|
|
Mode m_mode;
|
|
QMap<qint64, ScriptInfo*> m_scripts;
|
|
QMap<QScriptContext*, QStack<qint64> > m_contextProgramIds;
|
|
|
|
QString m_lastInteractiveCommand;
|
|
QString m_commandPrefix;
|
|
int m_stepDepth;
|
|
int m_currentFrameIndex;
|
|
int m_listLineNumber;
|
|
|
|
ScriptDebugger *q_ptr;
|
|
};
|
|
|
|
class ScriptInfo
|
|
{
|
|
public:
|
|
ScriptInfo(const QString &code, const QString &fileName, int lineNumber)
|
|
: m_code(code), m_fileName(fileName), m_lineNumber(lineNumber)
|
|
{ }
|
|
|
|
inline QString code() const
|
|
{ return m_code; }
|
|
inline QString fileName() const
|
|
{ return m_fileName; }
|
|
inline int lineNumber() const
|
|
{ return m_lineNumber; }
|
|
|
|
QString lineText(int lineNumber);
|
|
QMap<int, int> m_lineOffsets;
|
|
|
|
private:
|
|
int lineOffset(int lineNumber);
|
|
|
|
QString m_code;
|
|
QString m_fileName;
|
|
int m_lineNumber;
|
|
};
|
|
|
|
int ScriptInfo::lineOffset(int lineNumber)
|
|
{
|
|
QMap<int, int>::const_iterator it = m_lineOffsets.constFind(lineNumber);
|
|
if (it != m_lineOffsets.constEnd())
|
|
return it.value();
|
|
|
|
int offset;
|
|
it = m_lineOffsets.constFind(lineNumber - 1);
|
|
if (it != m_lineOffsets.constEnd()) {
|
|
offset = it.value();
|
|
offset = m_code.indexOf(QLatin1Char('\n'), offset);
|
|
if (offset != -1)
|
|
++offset;
|
|
m_lineOffsets.insert(lineNumber, offset);
|
|
} else {
|
|
int index;
|
|
it = m_lineOffsets.lowerBound(lineNumber);
|
|
--it;
|
|
if (it != m_lineOffsets.constBegin()) {
|
|
index = it.key();
|
|
offset = it.value();
|
|
} else {
|
|
index = m_lineNumber;
|
|
offset = 0;
|
|
}
|
|
int j = index;
|
|
for ( ; j < lineNumber; ++j) {
|
|
m_lineOffsets.insert(j, offset);
|
|
offset = m_code.indexOf(QLatin1Char('\n'), offset);
|
|
if (offset == -1)
|
|
break;
|
|
++offset;
|
|
}
|
|
m_lineOffsets.insert(j, offset);
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
QString ScriptInfo::lineText(int lineNumber)
|
|
{
|
|
int startOffset = lineOffset(lineNumber);
|
|
if (startOffset == -1)
|
|
return QString();
|
|
int endOffset = lineOffset(lineNumber + 1);
|
|
if (endOffset == -1)
|
|
return m_code.mid(startOffset);
|
|
else
|
|
return m_code.mid(startOffset, endOffset - startOffset - 1);
|
|
}
|
|
|
|
|
|
|
|
ScriptDebuggerPrivate::ScriptDebuggerPrivate(QScriptEngine *engine)
|
|
: QScriptEngineAgent(engine), m_mode(Run)
|
|
{
|
|
m_commandPrefix = QLatin1String(".");
|
|
m_bpManager = new ScriptBreakpointManager;
|
|
m_defaultInputStream = new QTextStream(stdin);
|
|
m_defaultOutputStream = new QTextStream(stdout);
|
|
m_defaultErrorStream = new QTextStream(stderr);
|
|
m_inputStream = m_defaultInputStream;
|
|
m_outputStream = m_defaultOutputStream;
|
|
m_errorStream = m_defaultErrorStream;
|
|
}
|
|
|
|
ScriptDebuggerPrivate::~ScriptDebuggerPrivate()
|
|
{
|
|
delete m_defaultInputStream;
|
|
delete m_defaultOutputStream;
|
|
delete m_defaultErrorStream;
|
|
delete m_bpManager;
|
|
qDeleteAll(m_scripts);
|
|
}
|
|
|
|
QString ScriptDebuggerPrivate::readLine()
|
|
{
|
|
return m_inputStream->readLine();
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::output(const QString &text)
|
|
{
|
|
*m_outputStream << text;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::message(const QString &text)
|
|
{
|
|
*m_outputStream << text << endl;
|
|
m_outputStream->flush();
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::errorMessage(const QString &text)
|
|
{
|
|
*m_errorStream << text << endl;
|
|
m_errorStream->flush();
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::setMode(Mode mode)
|
|
{
|
|
m_mode = mode;
|
|
}
|
|
|
|
ScriptDebuggerPrivate::Mode ScriptDebuggerPrivate::mode() const
|
|
{
|
|
return m_mode;
|
|
}
|
|
|
|
QScriptContext *ScriptDebuggerPrivate::frameContext(int index) const
|
|
{
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
for (int i = 0; i < index; ++i) {
|
|
ctx = ctx->parentContext();
|
|
if (!ctx)
|
|
break;
|
|
}
|
|
return ctx;
|
|
}
|
|
|
|
int ScriptDebuggerPrivate::currentFrameIndex() const
|
|
{
|
|
return m_currentFrameIndex;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::setCurrentFrameIndex(int index)
|
|
{
|
|
m_currentFrameIndex = index;
|
|
m_listLineNumber = -1;
|
|
}
|
|
|
|
int ScriptDebuggerPrivate::listLineNumber() const
|
|
{
|
|
return m_listLineNumber;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::setListLineNumber(int lineNumber)
|
|
{
|
|
m_listLineNumber = lineNumber;
|
|
}
|
|
|
|
QScriptContext *ScriptDebuggerPrivate::currentFrameContext() const
|
|
{
|
|
return frameContext(currentFrameIndex());
|
|
}
|
|
|
|
int ScriptDebuggerPrivate::frameCount() const
|
|
{
|
|
int count = 0;
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
while (ctx) {
|
|
++count;
|
|
ctx = ctx->parentContext();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
ScriptInfo *ScriptDebuggerPrivate::scriptInfo(QScriptContext *context) const
|
|
{
|
|
QStack<qint64> pids = m_contextProgramIds.value(context);
|
|
if (pids.isEmpty())
|
|
return 0;
|
|
return m_scripts.value(pids.top());
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::interactive()
|
|
{
|
|
setCurrentFrameIndex(0);
|
|
|
|
QString qsdbgPrompt = QString::fromLatin1("(qsdbg) ");
|
|
QString dotPrompt = QString::fromLatin1(".... ");
|
|
QString prompt = qsdbgPrompt;
|
|
|
|
QString code;
|
|
|
|
forever {
|
|
|
|
*m_outputStream << prompt;
|
|
m_outputStream->flush();
|
|
|
|
QString line = readLine();
|
|
|
|
if (code.isEmpty() && (line.isEmpty() || line.startsWith(m_commandPrefix))) {
|
|
if (line.isEmpty())
|
|
line = m_lastInteractiveCommand;
|
|
else
|
|
m_lastInteractiveCommand = line;
|
|
|
|
QStringList parts = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
|
if (!parts.isEmpty()) {
|
|
QString command = parts.takeFirst().mid(1);
|
|
if (executeCommand(command, parts))
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
if (line.isEmpty())
|
|
continue;
|
|
|
|
code += line;
|
|
code += QLatin1Char('\n');
|
|
|
|
if (line.trimmed().isEmpty()) {
|
|
continue;
|
|
|
|
} else if (! engine()->canEvaluate(code)) {
|
|
prompt = dotPrompt;
|
|
|
|
} else {
|
|
setMode(Run);
|
|
QScriptValue result = engine()->evaluate(code, QLatin1String("typein"));
|
|
|
|
code.clear();
|
|
prompt = qsdbgPrompt;
|
|
|
|
if (! result.isUndefined()) {
|
|
errorMessage(result.toString());
|
|
engine()->clearExceptions();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ScriptDebuggerPrivate::executeCommand(const QString &command, const QStringList &args)
|
|
{
|
|
if (command == QLatin1String("c")
|
|
|| command == QLatin1String("continue")) {
|
|
setMode(Run);
|
|
return true;
|
|
} else if (command == QLatin1String("s")
|
|
|| command == QLatin1String("step")) {
|
|
setMode(StepInto);
|
|
return true;
|
|
} else if (command == QLatin1String("n")
|
|
|| command == QLatin1String("next")) {
|
|
setMode(StepOver);
|
|
m_stepDepth = 0;
|
|
return true;
|
|
} else if (command == QLatin1String("f")
|
|
|| command == QLatin1String("frame")) {
|
|
bool ok = false;
|
|
int index = args.value(0).toInt(&ok);
|
|
if (ok) {
|
|
if (index < 0 || index >= frameCount()) {
|
|
errorMessage("No such frame.");
|
|
} else {
|
|
setCurrentFrameIndex(index);
|
|
QScriptContext *ctx = currentFrameContext();
|
|
message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
|
|
}
|
|
}
|
|
} else if (command == QLatin1String("bt")
|
|
|| command == QLatin1String("backtrace")) {
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
int index = -1;
|
|
while (ctx) {
|
|
++index;
|
|
QString line = ctx->toString();
|
|
message(QString::fromLatin1("#%0 %1").arg(index).arg(line));
|
|
ctx = ctx->parentContext();
|
|
}
|
|
} else if (command == QLatin1String("up")) {
|
|
int index = currentFrameIndex() + 1;
|
|
if (index == frameCount()) {
|
|
errorMessage(QString::fromLatin1("Initial frame selected; you cannot go up."));
|
|
} else {
|
|
setCurrentFrameIndex(index);
|
|
QScriptContext *ctx = currentFrameContext();
|
|
message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
|
|
}
|
|
} else if (command == QLatin1String("down")) {
|
|
int index = currentFrameIndex() - 1;
|
|
if (index < 0) {
|
|
errorMessage(QString::fromLatin1("Bottom (innermost) frame selected; you cannot go down."));
|
|
} else {
|
|
setCurrentFrameIndex(index);
|
|
QScriptContext *ctx = currentFrameContext();
|
|
message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString()));
|
|
}
|
|
} else if (command == QLatin1String("b")
|
|
|| command == QLatin1String("break")) {
|
|
QString str = args.value(0);
|
|
int colonIndex = str.indexOf(QLatin1Char(':'));
|
|
if (colonIndex != -1) {
|
|
// filename:line form
|
|
QString fileName = str.left(colonIndex);
|
|
int lineNumber = str.mid(colonIndex+1).toInt();
|
|
int id = m_bpManager->setBreakpoint(fileName, lineNumber);
|
|
message(QString::fromLatin1("Breakpoint %0 at %1, line %2.").arg(id+1).arg(fileName).arg(lineNumber));
|
|
} else {
|
|
// function
|
|
QScriptValue fun = engine()->globalObject().property(str);
|
|
if (fun.isFunction()) {
|
|
int id = m_bpManager->setBreakpoint(fun);
|
|
message(QString::fromLatin1("Breakpoint %0 at %1().").arg(id+1).arg(str));
|
|
}
|
|
}
|
|
} else if (command == QLatin1String("d")
|
|
|| command == QLatin1String("delete")) {
|
|
int id = args.value(0).toInt() - 1;
|
|
m_bpManager->removeBreakpoint(id);
|
|
} else if (command == QLatin1String("disable")) {
|
|
int id = args.value(0).toInt() - 1;
|
|
m_bpManager->setBreakpointEnabled(id, false);
|
|
} else if (command == QLatin1String("enable")) {
|
|
int id = args.value(0).toInt() - 1;
|
|
m_bpManager->setBreakpointEnabled(id, true);
|
|
} else if (command == QLatin1String("list")) {
|
|
QScriptContext *ctx = currentFrameContext();
|
|
ScriptInfo *progInfo = scriptInfo(ctx);
|
|
if (!progInfo) {
|
|
errorMessage("No source text available for this frame.");
|
|
} else {
|
|
QScriptContextInfo ctxInfo(ctx);
|
|
bool ok;
|
|
int line = args.value(0).toInt(&ok);
|
|
if (ok) {
|
|
line = qMax(1, line - 5);
|
|
} else {
|
|
line = listLineNumber();
|
|
if (line == -1)
|
|
line = qMax(progInfo->lineNumber(), ctxInfo.lineNumber() - 5);
|
|
}
|
|
for (int i = line; i < line + 10; ++i) {
|
|
message(QString::fromLatin1("%0\t%1").arg(i).arg(progInfo->lineText(i)));
|
|
}
|
|
setListLineNumber(line + 10);
|
|
}
|
|
} else if (command == QLatin1String("info")) {
|
|
if (args.size() < 1) {
|
|
} else {
|
|
QString what = args.value(0);
|
|
if (what == QLatin1String("locals")) {
|
|
QScriptValueIterator it(currentFrameContext()->activationObject());
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
QString line;
|
|
line.append(it.name());
|
|
line.append(QLatin1String(" = "));
|
|
line.append(safeValueToString(it.value()));
|
|
message(line);
|
|
}
|
|
}
|
|
}
|
|
} else if (command == QLatin1String("help")) {
|
|
message("continue - continue execution\n"
|
|
"step - step into statement\n"
|
|
"next - step over statement\n"
|
|
"list - show where you are\n"
|
|
"\n"
|
|
"break - set breakpoint\n"
|
|
"delete - remove breakpoint\n"
|
|
"disable - disable breakpoint\n"
|
|
"enable - enable breakpoint\n"
|
|
"\n"
|
|
"backtrace - show backtrace\n"
|
|
"up - one frame up\n"
|
|
"down - one frame down\n"
|
|
"frame - set frame\n"
|
|
"\n"
|
|
"info locals - show local variables");
|
|
} else {
|
|
errorMessage(QString::fromLatin1("Undefined command \"%0\". Try \"help\".")
|
|
.arg(command));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// QScriptEngineAgent interface
|
|
|
|
void ScriptDebuggerPrivate::scriptLoad(qint64 id, const QString &program,
|
|
const QString &fileName, int lineNumber)
|
|
{
|
|
ScriptInfo *info = new ScriptInfo(program, fileName, lineNumber);
|
|
m_scripts.insert(id, info);
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::scriptUnload(qint64 id)
|
|
{
|
|
ScriptInfo *info = m_scripts.take(id);
|
|
delete info;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::functionEntry(qint64 scriptId)
|
|
{
|
|
if (scriptId != -1) {
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
QStack<qint64> ids = m_contextProgramIds.value(ctx);
|
|
ids.push(scriptId);
|
|
m_contextProgramIds.insert(ctx, ids);
|
|
}
|
|
|
|
if (mode() == StepOver)
|
|
++m_stepDepth;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::functionExit(qint64 scriptId,
|
|
const QScriptValue &/*returnValue*/)
|
|
{
|
|
if (scriptId != -1) {
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
QStack<qint64> ids = m_contextProgramIds.value(ctx);
|
|
Q_ASSERT(!ids.isEmpty());
|
|
Q_ASSERT(ids.top() == scriptId);
|
|
ids.pop();
|
|
m_contextProgramIds.insert(ctx, ids);
|
|
}
|
|
|
|
if (mode() == StepOver)
|
|
--m_stepDepth;
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::positionChange(qint64 scriptId,
|
|
int lineNumber, int /*columnNumber*/)
|
|
{
|
|
ScriptInfo *info = 0;
|
|
bool enterInteractiveMode = false;
|
|
|
|
if (m_bpManager->hasBreakpoints()) {
|
|
// check if we hit a breakpoint
|
|
info = m_scripts.value(scriptId);
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
QScriptContextInfo ctxInfo(ctx);
|
|
QScriptValue callee = ctx->callee();
|
|
|
|
// try fileName:lineNumber
|
|
int bpid = m_bpManager->findBreakpoint(info->fileName(), lineNumber);
|
|
if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
|
|
message(QString::fromLatin1("Breakpoint %0 at %1:%2")
|
|
.arg(bpid + 1).arg(info->fileName()).arg(lineNumber));
|
|
if (m_bpManager->isBreakpointSingleShot(bpid))
|
|
m_bpManager->removeBreakpoint(bpid);
|
|
}
|
|
if (bpid == -1) {
|
|
// try function
|
|
bpid = m_bpManager->findBreakpoint(callee);
|
|
if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
|
|
message(QString::fromLatin1("Breakpoint %0, %1()")
|
|
.arg(bpid + 1).arg(ctxInfo.functionName()));
|
|
if (m_bpManager->isBreakpointSingleShot(bpid))
|
|
m_bpManager->removeBreakpoint(bpid);
|
|
}
|
|
}
|
|
if ((bpid == -1) && !ctxInfo.functionName().isEmpty()) {
|
|
// try functionName:fileName
|
|
bpid = m_bpManager->findBreakpoint(ctxInfo.functionName(), ctxInfo.fileName());
|
|
if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
|
|
message(QString::fromLatin1("Breakpoint %0, %1():%2").arg(bpid + 1)
|
|
.arg(ctxInfo.functionName()).arg(ctxInfo.fileName()));
|
|
if (m_bpManager->isBreakpointSingleShot(bpid))
|
|
m_bpManager->removeBreakpoint(bpid);
|
|
}
|
|
}
|
|
|
|
enterInteractiveMode = (bpid != -1);
|
|
}
|
|
|
|
switch (mode()) {
|
|
case Run:
|
|
break;
|
|
|
|
case StepInto:
|
|
enterInteractiveMode = true;
|
|
break;
|
|
|
|
case StepOver:
|
|
enterInteractiveMode = enterInteractiveMode || (m_stepDepth <= 0);
|
|
break;
|
|
}
|
|
|
|
if (enterInteractiveMode) {
|
|
if (!info)
|
|
info = m_scripts.value(scriptId);
|
|
Q_ASSERT(info);
|
|
message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(info->lineText(lineNumber)));
|
|
interactive();
|
|
}
|
|
}
|
|
|
|
void ScriptDebuggerPrivate::exceptionThrow(qint64 /*scriptId*/,
|
|
const QScriptValue &exception,
|
|
bool hasHandler)
|
|
{
|
|
if (!hasHandler) {
|
|
errorMessage(QString::fromLatin1("uncaught exception: %0").arg(exception.toString()));
|
|
QScriptContext *ctx = engine()->currentContext();
|
|
int lineNumber = QScriptContextInfo(ctx).lineNumber();
|
|
ScriptInfo *info = scriptInfo(ctx);
|
|
QString lineText = info ? info->lineText(lineNumber) : QString("(no source text available)");
|
|
message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(lineText));
|
|
interactive();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ScriptDebugger::ScriptDebugger(QScriptEngine *engine)
|
|
: d_ptr(new ScriptDebuggerPrivate(engine))
|
|
{
|
|
d_ptr->q_ptr = this;
|
|
engine->setAgent(d_ptr);
|
|
}
|
|
|
|
ScriptDebugger::ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd)
|
|
: d_ptr(&dd)
|
|
{
|
|
d_ptr->q_ptr = this;
|
|
engine->setAgent(d_ptr);
|
|
}
|
|
|
|
ScriptDebugger::~ScriptDebugger()
|
|
{
|
|
delete d_ptr;
|
|
d_ptr = 0;
|
|
}
|
|
|
|
void ScriptDebugger::breakAtNextStatement()
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->setMode(ScriptDebuggerPrivate::StepInto);
|
|
}
|
|
|
|
void ScriptDebugger::setBreakpoint(const QString &fileName, int lineNumber)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_bpManager->setBreakpoint(fileName, lineNumber);
|
|
}
|
|
|
|
void ScriptDebugger::setBreakpoint(const QString &functionName, const QString &fileName)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_bpManager->setBreakpoint(functionName, fileName);
|
|
}
|
|
|
|
void ScriptDebugger::setBreakpoint(const QScriptValue &function)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_bpManager->setBreakpoint(function);
|
|
}
|
|
|
|
QTextStream *ScriptDebugger::inputStream() const
|
|
{
|
|
Q_D(const ScriptDebugger);
|
|
return d->m_inputStream;
|
|
}
|
|
|
|
void ScriptDebugger::setInputStream(QTextStream *inputStream)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_inputStream = inputStream;
|
|
}
|
|
|
|
QTextStream *ScriptDebugger::outputStream() const
|
|
{
|
|
Q_D(const ScriptDebugger);
|
|
return d->m_outputStream;
|
|
}
|
|
|
|
void ScriptDebugger::setOutputStream(QTextStream *outputStream)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_outputStream = outputStream;
|
|
}
|
|
|
|
QTextStream *ScriptDebugger::errorStream() const
|
|
{
|
|
Q_D(const ScriptDebugger);
|
|
return d->m_errorStream;
|
|
}
|
|
|
|
void ScriptDebugger::setErrorStream(QTextStream *errorStream)
|
|
{
|
|
Q_D(ScriptDebugger);
|
|
d->m_errorStream = errorStream;
|
|
}
|