examples/script/qsdbg/scriptdebugger.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the examples of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "scriptdebugger.h"
       
    43 #include "scriptbreakpointmanager.h"
       
    44 
       
    45 #include <QtScript/QScriptEngine>
       
    46 #include <QtScript/QScriptEngineAgent>
       
    47 #include <QtScript/QScriptContextInfo>
       
    48 #include <QtScript/QScriptValueIterator>
       
    49 #include <QtCore/QTextStream>
       
    50 #include <QtCore/QStack>
       
    51 
       
    52 static QString safeValueToString(const QScriptValue &value)
       
    53 {
       
    54     if (value.isObject())
       
    55         return QLatin1String("[object Object]");
       
    56     else
       
    57         return value.toString();
       
    58 }
       
    59 
       
    60 class ScriptInfo;
       
    61 class ScriptBreakpointManager;
       
    62 
       
    63 class ScriptDebuggerPrivate
       
    64     : public QScriptEngineAgent
       
    65 {
       
    66     Q_DECLARE_PUBLIC(ScriptDebugger)
       
    67 public:
       
    68     enum Mode {
       
    69         Run,
       
    70         StepInto,
       
    71         StepOver
       
    72     };
       
    73 
       
    74     ScriptDebuggerPrivate(QScriptEngine *engine);
       
    75     ~ScriptDebuggerPrivate();
       
    76 
       
    77     // QScriptEngineAgent interface
       
    78     void scriptLoad(qint64 id, const QString &program,
       
    79                     const QString &fileName, int lineNumber);
       
    80     void scriptUnload(qint64 id);
       
    81 
       
    82     void positionChange(qint64 scriptId,
       
    83                         int lineNumber, int columnNumber);
       
    84 
       
    85     void functionEntry(qint64 scriptId);
       
    86     void functionExit(qint64 scriptId,
       
    87                       const QScriptValue &returnValue);
       
    88 
       
    89     void exceptionThrow(qint64 scriptId,
       
    90                         const QScriptValue &exception, bool hasHandler);
       
    91 
       
    92 
       
    93     void interactive();
       
    94     bool executeCommand(const QString &command, const QStringList &args);
       
    95 
       
    96     void setMode(Mode mode);
       
    97     Mode mode() const;
       
    98 
       
    99     int frameCount() const;
       
   100     void setCurrentFrameIndex(int index);
       
   101     int currentFrameIndex() const;
       
   102 
       
   103     QScriptContext *frameContext(int index) const;
       
   104     QScriptContext *currentFrameContext() const;
       
   105 
       
   106     ScriptInfo *scriptInfo(QScriptContext *context) const;
       
   107 
       
   108     int listLineNumber() const;
       
   109     void setListLineNumber(int lineNumber);
       
   110 
       
   111     QString readLine();
       
   112     void output(const QString &text);
       
   113     void message(const QString &text);
       
   114     void errorMessage(const QString &text);
       
   115 
       
   116     // attributes
       
   117     QTextStream *m_defaultInputStream;
       
   118     QTextStream *m_defaultOutputStream;
       
   119     QTextStream *m_defaultErrorStream;
       
   120     QTextStream *m_inputStream;
       
   121     QTextStream *m_outputStream;
       
   122     QTextStream *m_errorStream;
       
   123 
       
   124     ScriptBreakpointManager *m_bpManager;
       
   125     Mode m_mode;
       
   126     QMap<qint64, ScriptInfo*> m_scripts;
       
   127     QMap<QScriptContext*, QStack<qint64> > m_contextProgramIds;
       
   128 
       
   129     QString m_lastInteractiveCommand;
       
   130     QString m_commandPrefix;
       
   131     int m_stepDepth;
       
   132     int m_currentFrameIndex;
       
   133     int m_listLineNumber;
       
   134 
       
   135     ScriptDebugger *q_ptr;
       
   136 };
       
   137 
       
   138 class ScriptInfo
       
   139 {
       
   140 public:
       
   141     ScriptInfo(const QString &code, const QString &fileName, int lineNumber)
       
   142         : m_code(code), m_fileName(fileName), m_lineNumber(lineNumber)
       
   143         { }
       
   144 
       
   145     inline QString code() const
       
   146         { return m_code; }
       
   147     inline QString fileName() const
       
   148         { return m_fileName; }
       
   149     inline int lineNumber() const
       
   150         { return m_lineNumber; }
       
   151 
       
   152     QString lineText(int lineNumber);
       
   153     QMap<int, int> m_lineOffsets;
       
   154 
       
   155 private:
       
   156     int lineOffset(int lineNumber);
       
   157 
       
   158     QString m_code;
       
   159     QString m_fileName;
       
   160     int m_lineNumber;
       
   161 };
       
   162 
       
   163 int ScriptInfo::lineOffset(int lineNumber)
       
   164 {
       
   165     QMap<int, int>::const_iterator it = m_lineOffsets.constFind(lineNumber);
       
   166     if (it != m_lineOffsets.constEnd())
       
   167         return it.value();
       
   168 
       
   169     int offset;
       
   170     it = m_lineOffsets.constFind(lineNumber - 1);
       
   171     if (it != m_lineOffsets.constEnd()) {
       
   172         offset = it.value();
       
   173         offset = m_code.indexOf(QLatin1Char('\n'), offset);
       
   174         if (offset != -1)
       
   175             ++offset;
       
   176         m_lineOffsets.insert(lineNumber, offset);
       
   177     } else {
       
   178         int index;
       
   179         it = m_lineOffsets.lowerBound(lineNumber);
       
   180         --it;
       
   181         if (it != m_lineOffsets.constBegin()) {
       
   182             index = it.key();
       
   183             offset = it.value();
       
   184         } else {
       
   185             index = m_lineNumber;
       
   186             offset = 0;
       
   187         }
       
   188         int j = index;
       
   189         for ( ; j < lineNumber; ++j) {
       
   190             m_lineOffsets.insert(j, offset);
       
   191             offset = m_code.indexOf(QLatin1Char('\n'), offset);
       
   192             if (offset == -1)
       
   193                 break;
       
   194             ++offset;
       
   195         }
       
   196         m_lineOffsets.insert(j, offset);
       
   197     }
       
   198     return offset;
       
   199 }
       
   200 
       
   201 QString ScriptInfo::lineText(int lineNumber)
       
   202 {
       
   203     int startOffset = lineOffset(lineNumber);
       
   204     if (startOffset == -1)
       
   205         return QString();
       
   206     int endOffset = lineOffset(lineNumber + 1);
       
   207     if (endOffset == -1)
       
   208         return m_code.mid(startOffset);
       
   209     else
       
   210         return m_code.mid(startOffset, endOffset - startOffset - 1);
       
   211 }
       
   212 
       
   213 
       
   214 
       
   215 ScriptDebuggerPrivate::ScriptDebuggerPrivate(QScriptEngine *engine)
       
   216     : QScriptEngineAgent(engine), m_mode(Run)
       
   217 {
       
   218     m_commandPrefix = QLatin1String(".");
       
   219     m_bpManager = new ScriptBreakpointManager;
       
   220     m_defaultInputStream = new QTextStream(stdin);
       
   221     m_defaultOutputStream = new QTextStream(stdout);
       
   222     m_defaultErrorStream = new QTextStream(stderr);
       
   223     m_inputStream = m_defaultInputStream;
       
   224     m_outputStream = m_defaultOutputStream;
       
   225     m_errorStream = m_defaultErrorStream;
       
   226 }
       
   227 
       
   228 ScriptDebuggerPrivate::~ScriptDebuggerPrivate()
       
   229 {
       
   230     delete m_defaultInputStream;
       
   231     delete m_defaultOutputStream;
       
   232     delete m_defaultErrorStream;
       
   233     delete m_bpManager;
       
   234     qDeleteAll(m_scripts);
       
   235 }
       
   236 
       
   237 QString ScriptDebuggerPrivate::readLine()
       
   238 {
       
   239     return m_inputStream->readLine();
       
   240 }
       
   241 
       
   242 void ScriptDebuggerPrivate::output(const QString &text)
       
   243 {
       
   244     *m_outputStream << text;
       
   245 }
       
   246 
       
   247 void ScriptDebuggerPrivate::message(const QString &text)
       
   248 {
       
   249     *m_outputStream << text << endl;
       
   250     m_outputStream->flush();
       
   251 }
       
   252 
       
   253 void ScriptDebuggerPrivate::errorMessage(const QString &text)
       
   254 {
       
   255     *m_errorStream << text << endl;
       
   256     m_errorStream->flush();
       
   257 }
       
   258 
       
   259 void ScriptDebuggerPrivate::setMode(Mode mode)
       
   260 {
       
   261     m_mode = mode;
       
   262 }
       
   263 
       
   264 ScriptDebuggerPrivate::Mode ScriptDebuggerPrivate::mode() const
       
   265 {
       
   266     return m_mode;
       
   267 }
       
   268 
       
   269 QScriptContext *ScriptDebuggerPrivate::frameContext(int index) const
       
   270 {
       
   271     QScriptContext *ctx = engine()->currentContext();
       
   272     for (int i = 0; i < index; ++i) {
       
   273         ctx = ctx->parentContext();
       
   274         if (!ctx)
       
   275             break;
       
   276     }
       
   277     return ctx;
       
   278 }
       
   279 
       
   280 int ScriptDebuggerPrivate::currentFrameIndex() const
       
   281 {
       
   282     return m_currentFrameIndex;
       
   283 }
       
   284 
       
   285 void ScriptDebuggerPrivate::setCurrentFrameIndex(int index)
       
   286 {
       
   287     m_currentFrameIndex = index;
       
   288     m_listLineNumber = -1;
       
   289 }
       
   290 
       
   291 int ScriptDebuggerPrivate::listLineNumber() const
       
   292 {
       
   293     return m_listLineNumber;
       
   294 }
       
   295 
       
   296 void ScriptDebuggerPrivate::setListLineNumber(int lineNumber)
       
   297 {
       
   298     m_listLineNumber = lineNumber;
       
   299 }
       
   300 
       
   301 QScriptContext *ScriptDebuggerPrivate::currentFrameContext() const
       
   302 {
       
   303     return frameContext(currentFrameIndex());
       
   304 }
       
   305 
       
   306 int ScriptDebuggerPrivate::frameCount() const
       
   307 {
       
   308     int count = 0;
       
   309     QScriptContext *ctx = engine()->currentContext();
       
   310     while (ctx) {
       
   311         ++count;
       
   312         ctx = ctx->parentContext();
       
   313     }
       
   314     return count;
       
   315 }
       
   316 
       
   317 ScriptInfo *ScriptDebuggerPrivate::scriptInfo(QScriptContext *context) const
       
   318 {
       
   319     QStack<qint64> pids = m_contextProgramIds.value(context);
       
   320     if (pids.isEmpty())
       
   321         return 0;
       
   322     return m_scripts.value(pids.top());
       
   323 }
       
   324 
       
   325 void ScriptDebuggerPrivate::interactive()
       
   326 {
       
   327     setCurrentFrameIndex(0);
       
   328 
       
   329     QString qsdbgPrompt = QString::fromLatin1("(qsdbg) ");
       
   330     QString dotPrompt = QString::fromLatin1(".... ");
       
   331     QString prompt = qsdbgPrompt;
       
   332 
       
   333     QString code;
       
   334 
       
   335     forever {
       
   336 
       
   337          *m_outputStream << prompt;
       
   338         m_outputStream->flush();
       
   339 
       
   340         QString line = readLine();
       
   341 
       
   342         if (code.isEmpty() && (line.isEmpty() || line.startsWith(m_commandPrefix))) {
       
   343             if (line.isEmpty())
       
   344                 line = m_lastInteractiveCommand;
       
   345             else
       
   346                 m_lastInteractiveCommand = line;
       
   347 
       
   348             QStringList parts = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   349             if (!parts.isEmpty()) {
       
   350                 QString command = parts.takeFirst().mid(1);
       
   351                 if (executeCommand(command, parts))
       
   352                     break;
       
   353             }
       
   354 
       
   355         } else {
       
   356             if (line.isEmpty())
       
   357                 continue;
       
   358 
       
   359             code += line;
       
   360             code += QLatin1Char('\n');
       
   361 
       
   362             if (line.trimmed().isEmpty()) {
       
   363                 continue;
       
   364 
       
   365             } else if (! engine()->canEvaluate(code)) {
       
   366                 prompt = dotPrompt;
       
   367 
       
   368             } else {
       
   369                 setMode(Run);
       
   370                 QScriptValue result = engine()->evaluate(code, QLatin1String("typein"));
       
   371 
       
   372                 code.clear();
       
   373                 prompt = qsdbgPrompt;
       
   374 
       
   375                 if (! result.isUndefined()) {
       
   376                     errorMessage(result.toString());
       
   377                     engine()->clearExceptions();
       
   378                 }
       
   379             }
       
   380         }
       
   381     }
       
   382 }
       
   383 
       
   384 bool ScriptDebuggerPrivate::executeCommand(const QString &command, const QStringList &args)
       
   385 {
       
   386     if (command == QLatin1String("c")
       
   387         || command == QLatin1String("continue")) {
       
   388         setMode(Run);
       
   389         return true;
       
   390     } else if (command == QLatin1String("s")
       
   391                || command == QLatin1String("step")) {
       
   392         setMode(StepInto);
       
   393         return true;
       
   394     } else if (command == QLatin1String("n")
       
   395                || command == QLatin1String("next")) {
       
   396         setMode(StepOver);
       
   397         m_stepDepth = 0;
       
   398         return true;
       
   399     } else if (command == QLatin1String("f")
       
   400                || command == QLatin1String("frame")) {
       
   401         bool ok = false;
       
   402         int index = args.value(0).toInt(&ok);
       
   403         if (ok) {
       
   404             if (index < 0 || index >= frameCount()) {
       
   405                 errorMessage("No such frame.");
       
   406             } else {
       
   407                 setCurrentFrameIndex(index);
       
   408                 QScriptContext *ctx = currentFrameContext();
       
   409                 message(QString::fromLatin1("#%0  %1").arg(index).arg(ctx->toString()));
       
   410             }
       
   411         }
       
   412     } else if (command == QLatin1String("bt")
       
   413                || command == QLatin1String("backtrace")) {
       
   414         QScriptContext *ctx = engine()->currentContext();
       
   415         int index = -1;
       
   416         while (ctx) {
       
   417             ++index;
       
   418             QString line = ctx->toString();
       
   419             message(QString::fromLatin1("#%0  %1").arg(index).arg(line));
       
   420             ctx = ctx->parentContext();
       
   421         }
       
   422     } else if (command == QLatin1String("up")) {
       
   423         int index = currentFrameIndex() + 1;
       
   424         if (index == frameCount()) {
       
   425             errorMessage(QString::fromLatin1("Initial frame selected; you cannot go up."));
       
   426         } else {
       
   427             setCurrentFrameIndex(index);
       
   428             QScriptContext *ctx = currentFrameContext();
       
   429             message(QString::fromLatin1("#%0  %1").arg(index).arg(ctx->toString()));
       
   430         }
       
   431     } else if (command == QLatin1String("down")) {
       
   432         int index = currentFrameIndex() - 1;
       
   433         if (index < 0) {
       
   434             errorMessage(QString::fromLatin1("Bottom (innermost) frame selected; you cannot go down."));
       
   435         } else {
       
   436             setCurrentFrameIndex(index);
       
   437             QScriptContext *ctx = currentFrameContext();
       
   438             message(QString::fromLatin1("#%0  %1").arg(index).arg(ctx->toString()));
       
   439         }
       
   440     } else if (command == QLatin1String("b")
       
   441                || command == QLatin1String("break")) {
       
   442         QString str = args.value(0);
       
   443         int colonIndex = str.indexOf(QLatin1Char(':'));
       
   444         if (colonIndex != -1) {
       
   445             // filename:line form
       
   446             QString fileName = str.left(colonIndex);
       
   447             int lineNumber = str.mid(colonIndex+1).toInt();
       
   448             int id = m_bpManager->setBreakpoint(fileName, lineNumber);
       
   449             message(QString::fromLatin1("Breakpoint %0 at %1, line %2.").arg(id+1).arg(fileName).arg(lineNumber));
       
   450         } else {
       
   451             // function
       
   452             QScriptValue fun = engine()->globalObject().property(str);
       
   453             if (fun.isFunction()) {
       
   454                 int id = m_bpManager->setBreakpoint(fun);
       
   455                 message(QString::fromLatin1("Breakpoint %0 at %1().").arg(id+1).arg(str));
       
   456             }
       
   457         }
       
   458     } else if (command == QLatin1String("d")
       
   459                || command == QLatin1String("delete")) {
       
   460         int id = args.value(0).toInt() - 1;
       
   461         m_bpManager->removeBreakpoint(id);
       
   462     } else if (command == QLatin1String("disable")) {
       
   463         int id = args.value(0).toInt() - 1;
       
   464         m_bpManager->setBreakpointEnabled(id, false);
       
   465     } else if (command == QLatin1String("enable")) {
       
   466         int id = args.value(0).toInt() - 1;
       
   467         m_bpManager->setBreakpointEnabled(id, true);
       
   468     } else if (command == QLatin1String("list")) {
       
   469         QScriptContext *ctx = currentFrameContext();
       
   470         ScriptInfo *progInfo = scriptInfo(ctx);
       
   471         if (!progInfo) {
       
   472             errorMessage("No source text available for this frame.");
       
   473         } else {
       
   474             QScriptContextInfo ctxInfo(ctx);
       
   475             bool ok;
       
   476             int line = args.value(0).toInt(&ok);
       
   477             if (ok) {
       
   478                 line = qMax(1, line - 5);
       
   479             } else {
       
   480                 line = listLineNumber();
       
   481                 if (line == -1)
       
   482                     line = qMax(progInfo->lineNumber(), ctxInfo.lineNumber() - 5);
       
   483             }
       
   484             for (int i = line; i < line + 10; ++i) {
       
   485                 message(QString::fromLatin1("%0\t%1").arg(i).arg(progInfo->lineText(i)));
       
   486             }
       
   487             setListLineNumber(line + 10);
       
   488         }
       
   489     } else if (command == QLatin1String("info")) {
       
   490         if (args.size() < 1) {
       
   491         } else {
       
   492             QString what = args.value(0);
       
   493             if (what == QLatin1String("locals")) {
       
   494                 QScriptValueIterator it(currentFrameContext()->activationObject());
       
   495                 while (it.hasNext()) {
       
   496                     it.next();
       
   497                     QString line;
       
   498                     line.append(it.name());
       
   499                     line.append(QLatin1String(" = "));
       
   500                     line.append(safeValueToString(it.value()));
       
   501                     message(line);
       
   502                 }
       
   503             }
       
   504         }
       
   505     } else if (command == QLatin1String("help")) {
       
   506         message("continue - continue execution\n"
       
   507                 "step     - step into statement\n"
       
   508                 "next     - step over statement\n"
       
   509                 "list     - show where you are\n"
       
   510                 "\n"
       
   511                 "break    - set breakpoint\n"
       
   512                 "delete   - remove breakpoint\n"
       
   513                 "disable  - disable breakpoint\n"
       
   514                 "enable   - enable breakpoint\n"
       
   515                 "\n"
       
   516                 "backtrace - show backtrace\n"
       
   517                 "up       - one frame up\n"
       
   518                 "down     - one frame down\n"
       
   519                 "frame    - set frame\n"
       
   520                 "\n"
       
   521                 "info locals - show local variables");
       
   522     } else {
       
   523         errorMessage(QString::fromLatin1("Undefined command \"%0\". Try \"help\".")
       
   524                      .arg(command));
       
   525     }
       
   526 
       
   527     return false;
       
   528 }
       
   529 
       
   530 
       
   531 // QScriptEngineAgent interface
       
   532 
       
   533 void ScriptDebuggerPrivate::scriptLoad(qint64 id, const QString &program,
       
   534                                        const QString &fileName, int lineNumber)
       
   535 {
       
   536     ScriptInfo *info = new ScriptInfo(program, fileName, lineNumber);
       
   537     m_scripts.insert(id, info);
       
   538 }
       
   539 
       
   540 void ScriptDebuggerPrivate::scriptUnload(qint64 id)
       
   541 {
       
   542     ScriptInfo *info = m_scripts.take(id);
       
   543     delete info;
       
   544 }
       
   545 
       
   546 void ScriptDebuggerPrivate::functionEntry(qint64 scriptId)
       
   547 {
       
   548     if (scriptId != -1) {
       
   549         QScriptContext *ctx = engine()->currentContext();
       
   550         QStack<qint64> ids = m_contextProgramIds.value(ctx);
       
   551         ids.push(scriptId);
       
   552         m_contextProgramIds.insert(ctx, ids);
       
   553     }
       
   554 
       
   555     if (mode() == StepOver)
       
   556         ++m_stepDepth;
       
   557 }
       
   558 
       
   559 void ScriptDebuggerPrivate::functionExit(qint64 scriptId,
       
   560                                          const QScriptValue &/*returnValue*/)
       
   561 {
       
   562     if (scriptId != -1) {
       
   563         QScriptContext *ctx = engine()->currentContext();
       
   564         QStack<qint64> ids = m_contextProgramIds.value(ctx);
       
   565         Q_ASSERT(!ids.isEmpty());
       
   566         Q_ASSERT(ids.top() == scriptId);
       
   567         ids.pop();
       
   568         m_contextProgramIds.insert(ctx, ids);
       
   569     }
       
   570 
       
   571     if (mode() == StepOver)
       
   572         --m_stepDepth;
       
   573 }
       
   574 
       
   575 void ScriptDebuggerPrivate::positionChange(qint64 scriptId,
       
   576                                            int lineNumber, int /*columnNumber*/)
       
   577 {
       
   578     ScriptInfo *info = 0;
       
   579     bool enterInteractiveMode = false;
       
   580 
       
   581     if (m_bpManager->hasBreakpoints()) {
       
   582         // check if we hit a breakpoint
       
   583         info = m_scripts.value(scriptId);
       
   584         QScriptContext *ctx = engine()->currentContext();
       
   585         QScriptContextInfo ctxInfo(ctx);
       
   586         QScriptValue callee = ctx->callee();
       
   587 
       
   588         // try fileName:lineNumber
       
   589         int bpid = m_bpManager->findBreakpoint(info->fileName(), lineNumber);
       
   590         if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
       
   591             message(QString::fromLatin1("Breakpoint %0 at %1:%2")
       
   592                     .arg(bpid + 1).arg(info->fileName()).arg(lineNumber));
       
   593             if (m_bpManager->isBreakpointSingleShot(bpid))
       
   594                 m_bpManager->removeBreakpoint(bpid);
       
   595         }
       
   596         if (bpid == -1) {
       
   597             // try function
       
   598             bpid = m_bpManager->findBreakpoint(callee);
       
   599             if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
       
   600                 message(QString::fromLatin1("Breakpoint %0, %1()")
       
   601                         .arg(bpid + 1).arg(ctxInfo.functionName()));
       
   602                 if (m_bpManager->isBreakpointSingleShot(bpid))
       
   603                     m_bpManager->removeBreakpoint(bpid);
       
   604             }
       
   605         }
       
   606         if ((bpid == -1) && !ctxInfo.functionName().isEmpty()) {
       
   607             // try functionName:fileName
       
   608             bpid = m_bpManager->findBreakpoint(ctxInfo.functionName(), ctxInfo.fileName());
       
   609             if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) {
       
   610                 message(QString::fromLatin1("Breakpoint %0, %1():%2").arg(bpid + 1)
       
   611                         .arg(ctxInfo.functionName()).arg(ctxInfo.fileName()));
       
   612                 if (m_bpManager->isBreakpointSingleShot(bpid))
       
   613                     m_bpManager->removeBreakpoint(bpid);
       
   614             }
       
   615         }
       
   616 
       
   617         enterInteractiveMode = (bpid != -1);
       
   618     }
       
   619 
       
   620     switch (mode()) {
       
   621     case Run:
       
   622         break;
       
   623 
       
   624     case StepInto:
       
   625         enterInteractiveMode = true;
       
   626         break;
       
   627 
       
   628     case StepOver:
       
   629         enterInteractiveMode = enterInteractiveMode || (m_stepDepth <= 0);
       
   630         break;
       
   631     }
       
   632 
       
   633     if (enterInteractiveMode) {
       
   634         if (!info)
       
   635             info = m_scripts.value(scriptId);
       
   636         Q_ASSERT(info);        
       
   637         message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(info->lineText(lineNumber)));
       
   638         interactive();
       
   639     }
       
   640 }
       
   641 
       
   642 void ScriptDebuggerPrivate::exceptionThrow(qint64 /*scriptId*/,
       
   643                                            const QScriptValue &exception,
       
   644                                            bool hasHandler)
       
   645 {
       
   646     if (!hasHandler) {
       
   647         errorMessage(QString::fromLatin1("uncaught exception: %0").arg(exception.toString()));
       
   648         QScriptContext *ctx = engine()->currentContext();
       
   649         int lineNumber = QScriptContextInfo(ctx).lineNumber();
       
   650         ScriptInfo *info = scriptInfo(ctx);
       
   651         QString lineText = info ? info->lineText(lineNumber) : QString("(no source text available)");
       
   652         message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(lineText));
       
   653         interactive();
       
   654     }
       
   655 }
       
   656 
       
   657 
       
   658 
       
   659 ScriptDebugger::ScriptDebugger(QScriptEngine *engine)
       
   660     : d_ptr(new ScriptDebuggerPrivate(engine))
       
   661 {
       
   662     d_ptr->q_ptr = this;
       
   663     engine->setAgent(d_ptr);
       
   664 }
       
   665 
       
   666 ScriptDebugger::ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd)
       
   667     : d_ptr(&dd)
       
   668 {
       
   669     d_ptr->q_ptr = this;
       
   670     engine->setAgent(d_ptr);
       
   671 }
       
   672 
       
   673 ScriptDebugger::~ScriptDebugger()
       
   674 {
       
   675     delete d_ptr;
       
   676     d_ptr = 0;
       
   677 }
       
   678 
       
   679 void ScriptDebugger::breakAtNextStatement()
       
   680 {
       
   681     Q_D(ScriptDebugger);
       
   682     d->setMode(ScriptDebuggerPrivate::StepInto);
       
   683 }
       
   684 
       
   685 void ScriptDebugger::setBreakpoint(const QString &fileName, int lineNumber)
       
   686 {
       
   687     Q_D(ScriptDebugger);
       
   688     d->m_bpManager->setBreakpoint(fileName, lineNumber);
       
   689 }
       
   690 
       
   691 void ScriptDebugger::setBreakpoint(const QString &functionName, const QString &fileName)
       
   692 {
       
   693     Q_D(ScriptDebugger);
       
   694     d->m_bpManager->setBreakpoint(functionName, fileName);
       
   695 }
       
   696 
       
   697 void ScriptDebugger::setBreakpoint(const QScriptValue &function)
       
   698 {
       
   699     Q_D(ScriptDebugger);
       
   700     d->m_bpManager->setBreakpoint(function);
       
   701 }
       
   702 
       
   703 QTextStream *ScriptDebugger::inputStream() const
       
   704 {
       
   705     Q_D(const ScriptDebugger);
       
   706     return d->m_inputStream;
       
   707 }
       
   708 
       
   709 void ScriptDebugger::setInputStream(QTextStream *inputStream)
       
   710 {
       
   711     Q_D(ScriptDebugger);
       
   712     d->m_inputStream = inputStream;
       
   713 }
       
   714 
       
   715 QTextStream *ScriptDebugger::outputStream() const
       
   716 {
       
   717     Q_D(const ScriptDebugger);
       
   718     return d->m_outputStream;
       
   719 }
       
   720 
       
   721 void ScriptDebugger::setOutputStream(QTextStream *outputStream)
       
   722 {
       
   723     Q_D(ScriptDebugger);
       
   724     d->m_outputStream = outputStream;
       
   725 }
       
   726 
       
   727 QTextStream *ScriptDebugger::errorStream() const
       
   728 {
       
   729     Q_D(const ScriptDebugger);
       
   730     return d->m_errorStream;
       
   731 }
       
   732 
       
   733 void ScriptDebugger::setErrorStream(QTextStream *errorStream)
       
   734 {
       
   735     Q_D(ScriptDebugger);
       
   736     d->m_errorStream = errorStream;
       
   737 }