src/scripttools/debugging/qscriptdebuggerbackend.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 QtSCriptTools module 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 "qscriptdebuggerbackend_p.h"
       
    43 #include "qscriptdebuggerbackend_p_p.h"
       
    44 #include "qscriptdebuggeragent_p.h"
       
    45 #include "qscriptdebuggercommandexecutor_p.h"
       
    46 #include "qscriptdebuggerevent_p.h"
       
    47 #include "qscriptdebuggervalue_p.h"
       
    48 #include "qscriptscriptdata_p.h"
       
    49 #include "qscriptbreakpointdata_p.h"
       
    50 #include "qscriptobjectsnapshot_p.h"
       
    51 
       
    52 #include <QtScript/qscriptengine.h>
       
    53 #include <QtScript/qscriptcontextinfo.h>
       
    54 #include <QtScript/qscriptvalueiterator.h>
       
    55 
       
    56 #include <QtCore/qcoreapplication.h>
       
    57 #include <QtCore/qdebug.h>
       
    58 
       
    59 Q_DECLARE_METATYPE(QScriptDebuggerValue)
       
    60 Q_DECLARE_METATYPE(QScriptDebuggerBackendPrivate*)
       
    61 
       
    62 QT_BEGIN_NAMESPACE
       
    63 
       
    64 /*!
       
    65   \since 4.5
       
    66   \class QScriptDebuggerBackend
       
    67   \internal
       
    68 
       
    69   \brief The QScriptDebuggerBackend class is the base class of debugger back-ends.
       
    70 
       
    71   QScriptDebuggerBackend builds on the QScriptDebuggerAgent class.
       
    72 
       
    73   This class is usually used together with the QScriptDebuggerFrontend
       
    74   class, in order to form a (front-end, back-end) pair.
       
    75 
       
    76   Call attachTo() to attach to a QScriptEngine object. Call detach()
       
    77   to detach from the current engine.
       
    78 
       
    79   Call stepInto() to step into the next script statement; call stepOver()
       
    80   to step over the next script statement; and call stepOut() to step out
       
    81   of the currently executing script function. An event() will be generated
       
    82   when the stepping is completed.
       
    83 
       
    84   Call runToLocation() to execute script statements until a certain
       
    85   location has been reached. An event() will be generated when the location
       
    86   has been reached.
       
    87 
       
    88   Call interruptEvaluation() to request that evaluation should be
       
    89   interrupted. An event() will be generated upon the next script
       
    90   statement that is reached.
       
    91 
       
    92   Call continueEvalution() to allow script evaluation to continue.
       
    93 
       
    94   Call setBreakpoint() to set a breakpoint. A breakpoint event() will
       
    95   be generated when a breakpoint is hit. Call deleteBreakpoint() to
       
    96   delete a breakpoint. Call modifyBreakpoint() to change the state of
       
    97   an existing breakpoint.
       
    98 
       
    99   Call contextCount() to obtain the number of active contexts
       
   100   (frames). Call context() to obtain a pointer to a QScriptContext.
       
   101 
       
   102   \section1 Subclassing
       
   103 
       
   104   When subclassing QScriptDebuggerBackend, you must implement the pure
       
   105   virtual event() function. This function typically forwards the event
       
   106   to a QScriptDebuggerFrontend object. For most type of events,
       
   107   event() should block until the back-end is instructed to resume
       
   108   execution (e.g. until continueEvalution() is called). You must
       
   109   implement resume(), which is responsible for making event() return.
       
   110 
       
   111   \sa QScriptDebuggerFrontend, QScriptDebuggerEvent
       
   112 */
       
   113 
       
   114 // helper class that's used to handle our custom Qt events
       
   115 class QScriptDebuggerBackendEventReceiver : public QObject
       
   116 {
       
   117 public:
       
   118     QScriptDebuggerBackendEventReceiver(QScriptDebuggerBackendPrivate *backend,
       
   119                                         QObject *parent = 0)
       
   120         : QObject(parent), m_backend(backend) {}
       
   121     ~QScriptDebuggerBackendEventReceiver() {}
       
   122 
       
   123     bool event(QEvent *e)
       
   124     {
       
   125         return m_backend->event(e);
       
   126     }
       
   127 
       
   128 private:
       
   129     QScriptDebuggerBackendPrivate *m_backend;
       
   130 };
       
   131 
       
   132 
       
   133 QScriptDebuggerBackendPrivate::QScriptDebuggerBackendPrivate()
       
   134     : agent(0), commandExecutor(0),
       
   135         pendingEvaluateContextIndex(-1), pendingEvaluateLineNumber(-1),
       
   136         ignoreExceptions(false),
       
   137         nextScriptValueIteratorId(0), nextScriptObjectSnapshotId(0),
       
   138         eventReceiver(0),
       
   139         q_ptr(0) // q_ptr will be set later by QScriptDebuggerBackend constructor
       
   140 {
       
   141 }
       
   142 
       
   143 QScriptDebuggerBackendPrivate::~QScriptDebuggerBackendPrivate()
       
   144 {
       
   145     if (agent)
       
   146         agent->nullifyBackendPointer();
       
   147     delete commandExecutor;
       
   148     delete eventReceiver;
       
   149     qDeleteAll(scriptValueIterators);
       
   150     qDeleteAll(scriptObjectSnapshots);
       
   151 }
       
   152 
       
   153 void QScriptDebuggerBackendPrivate::postEvent(QEvent *e)
       
   154 {
       
   155     if (!eventReceiver) {
       
   156         eventReceiver = new QScriptDebuggerBackendEventReceiver(this);
       
   157         eventReceiver->moveToThread(agent->engine()->thread());
       
   158     }
       
   159     QCoreApplication::postEvent(eventReceiver, e);
       
   160 }
       
   161 
       
   162 bool QScriptDebuggerBackendPrivate::event(QEvent *e)
       
   163 {
       
   164     if (e->type() == QEvent::User+1) {
       
   165         QScriptDebuggerEventEvent *de = static_cast<QScriptDebuggerEventEvent*>(e);
       
   166         q_func()->event(de->event());
       
   167         return true;
       
   168     }
       
   169     return false;
       
   170 }
       
   171 
       
   172 void QScriptDebuggerBackendPrivate::agentDestroyed(QScriptDebuggerAgent *ag)
       
   173 {
       
   174     // Since agents are owned by the script engine, this in practice means
       
   175     // that the engine has been destroyed. Invalidate our pointer so we
       
   176     // don't crash later.
       
   177     if (agent == ag)
       
   178         agent = 0;
       
   179 }
       
   180 
       
   181 /*!
       
   182   The agent calls this function when it has completed a step
       
   183   operation.
       
   184 */
       
   185 void QScriptDebuggerBackendPrivate::stepped(qint64 scriptId,
       
   186                                             int lineNumber,
       
   187                                             int columnNumber,
       
   188                                             const QScriptValue &result)
       
   189 {
       
   190     Q_Q(QScriptDebuggerBackend);
       
   191     QScriptDebuggerEvent e(QScriptDebuggerEvent::SteppingFinished,
       
   192                            scriptId, lineNumber, columnNumber);
       
   193     e.setFileName(agent->scriptData(scriptId).fileName());
       
   194     QScriptDebuggerValue value(result);
       
   195     e.setScriptValue(value);
       
   196     if (!result.isUndefined())
       
   197         e.setMessage(result.toString()); // for convenience -- we always need it
       
   198     q->event(e);
       
   199 }
       
   200 
       
   201 /*!
       
   202   The agent calls this function when it has run to a particular
       
   203   location.
       
   204 */
       
   205 void QScriptDebuggerBackendPrivate::locationReached(qint64 scriptId,
       
   206                                                     int lineNumber,
       
   207                                                     int columnNumber)
       
   208 {
       
   209     Q_Q(QScriptDebuggerBackend);
       
   210     QScriptDebuggerEvent e(QScriptDebuggerEvent::LocationReached,
       
   211                            scriptId, lineNumber, columnNumber);
       
   212     e.setFileName(agent->scriptData(scriptId).fileName());
       
   213     q->event(e);
       
   214 }
       
   215 
       
   216 /*!
       
   217   The agent calls this function when evaluation has been interrupted.
       
   218 */
       
   219 void QScriptDebuggerBackendPrivate::interrupted(qint64 scriptId,
       
   220                                                 int lineNumber,
       
   221                                                 int columnNumber)
       
   222 {
       
   223     Q_Q(QScriptDebuggerBackend);
       
   224     QScriptDebuggerEvent e(QScriptDebuggerEvent::Interrupted,
       
   225                            scriptId, lineNumber, columnNumber);
       
   226     e.setFileName(agent->scriptData(scriptId).fileName());
       
   227     q->event(e);
       
   228 }
       
   229 
       
   230 /*!
       
   231   The agent calls this function when a breakpoint has been triggered.
       
   232 */
       
   233 void QScriptDebuggerBackendPrivate::breakpoint(qint64 scriptId,
       
   234                                                int lineNumber,
       
   235                                                int columnNumber,
       
   236                                                int breakpointId)
       
   237 {
       
   238     Q_Q(QScriptDebuggerBackend);
       
   239     QScriptDebuggerEvent e(QScriptDebuggerEvent::Breakpoint,
       
   240                            scriptId, lineNumber, columnNumber);
       
   241     e.setFileName(agent->scriptData(scriptId).fileName());
       
   242     e.setBreakpointId(breakpointId);
       
   243     q->event(e);
       
   244 }
       
   245 
       
   246 /*!
       
   247   The agent calls this function when an uncaught exception has
       
   248   occurred.
       
   249 */
       
   250 void QScriptDebuggerBackendPrivate::exception(qint64 scriptId,
       
   251                                               const QScriptValue &exception,
       
   252                                               bool hasHandler)
       
   253 {
       
   254     Q_Q(QScriptDebuggerBackend);
       
   255     if (ignoreExceptions) {
       
   256         // don't care (it's caught by us)
       
   257         return;
       
   258     }
       
   259     QScriptDebuggerEvent e(QScriptDebuggerEvent::Exception);
       
   260     e.setScriptId(scriptId);
       
   261     e.setFileName(agent->scriptData(scriptId).fileName());
       
   262     e.setMessage(exception.toString());
       
   263     e.setHasExceptionHandler(hasHandler);
       
   264     int lineNumber = -1;
       
   265     QString fileName;
       
   266     if (exception.property(QLatin1String("lineNumber")).isNumber())
       
   267         lineNumber = exception.property(QLatin1String("lineNumber")).toInt32();
       
   268     if (exception.property(QLatin1String("fileName")).isString())
       
   269         fileName = exception.property(QLatin1String("fileName")).toString();
       
   270     if (lineNumber == -1) {
       
   271         QScriptContextInfo info(q->engine()->currentContext());
       
   272         lineNumber = info.lineNumber();
       
   273         fileName = info.fileName();
       
   274     }
       
   275     if (lineNumber != -1)
       
   276         e.setLineNumber(lineNumber);
       
   277     if (!fileName.isEmpty())
       
   278         e.setFileName(fileName);
       
   279     QScriptDebuggerValue value(exception);
       
   280     e.setScriptValue(value);
       
   281     q->event(e);
       
   282 }
       
   283 
       
   284 QScriptValue QScriptDebuggerBackendPrivate::trace(QScriptContext *context,
       
   285                                                   QScriptEngine *engine)
       
   286 {
       
   287     QScriptValue data = context->callee().data();
       
   288     QScriptDebuggerBackendPrivate *self = qscriptvalue_cast<QScriptDebuggerBackendPrivate*>(data);
       
   289     if (!self)
       
   290         return engine->undefinedValue();
       
   291     QString str;
       
   292     for (int i = 0; i < context->argumentCount(); ++i) {
       
   293         if (i > 0)
       
   294             str.append(QLatin1Char(' '));
       
   295         str.append(context->argument(i).toString());
       
   296     }
       
   297     QScriptDebuggerEvent e(QScriptDebuggerEvent::Trace);
       
   298     e.setMessage(str);
       
   299     self->q_func()->event(e);
       
   300     return engine->undefinedValue();
       
   301 }
       
   302 
       
   303 QScriptValue QScriptDebuggerBackendPrivate::qsassert(QScriptContext *context,
       
   304                                                      QScriptEngine *engine)
       
   305 {
       
   306     QScriptValue arg = context->argument(0);
       
   307     if (arg.toBoolean())
       
   308         return arg;
       
   309     QScriptContextInfo info(context->parentContext());
       
   310     QString msg;
       
   311     QString fileName = info.fileName();
       
   312     if (fileName.isEmpty())
       
   313         fileName = QString::fromLatin1("<anonymous script, id=%0>").arg(info.scriptId());
       
   314     msg.append(fileName);
       
   315     msg.append(QLatin1Char(':'));
       
   316     msg.append(QString::number(info.lineNumber()));
       
   317     msg.append(QString::fromLatin1(": Assertion failed"));
       
   318     for (int i = 1; i < context->argumentCount(); ++i) {
       
   319         if (i == 1)
       
   320             msg.append(QLatin1Char(':'));
       
   321         msg.append(QLatin1Char(' '));
       
   322         msg.append(context->argument(i).toString());
       
   323     }
       
   324     QScriptValue err = context->throwError(msg);
       
   325     err.setProperty(QString::fromLatin1("name"), QScriptValue(engine, QString::fromLatin1("AssertionError")));
       
   326     return err;
       
   327 }
       
   328 
       
   329 QScriptValue QScriptDebuggerBackendPrivate::fileName(QScriptContext *context,
       
   330                                                      QScriptEngine *engine)
       
   331 {
       
   332     QScriptContextInfo info(context->parentContext());
       
   333     QString fn = info.fileName();
       
   334     if (fn.isEmpty())
       
   335         return engine->undefinedValue();
       
   336     return QScriptValue(engine, fn);
       
   337 }
       
   338 
       
   339 QScriptValue QScriptDebuggerBackendPrivate::lineNumber(QScriptContext *context,
       
   340                                                        QScriptEngine *engine)
       
   341 {
       
   342     QScriptContextInfo info(context->parentContext());
       
   343     return QScriptValue(engine, info.lineNumber());
       
   344 }
       
   345 
       
   346 /*!
       
   347   The agent calls this function when the engine has reached a
       
   348   "debugger" statement.
       
   349 */
       
   350 void QScriptDebuggerBackendPrivate::debuggerInvocationRequest(
       
   351     qint64 scriptId, int lineNumber, int columnNumber)
       
   352 {
       
   353     Q_Q(QScriptDebuggerBackend);
       
   354     QScriptDebuggerEvent e(QScriptDebuggerEvent::DebuggerInvocationRequest,
       
   355                            scriptId, lineNumber, columnNumber);
       
   356     e.setFileName(agent->scriptData(scriptId).fileName());
       
   357     q->event(e);
       
   358 }
       
   359 
       
   360 void QScriptDebuggerBackendPrivate::forcedReturn(
       
   361     qint64 scriptId, int lineNumber, int columnNumber,
       
   362     const QScriptValue &value)
       
   363 {
       
   364     Q_Q(QScriptDebuggerBackend);
       
   365     QScriptDebuggerEvent e(QScriptDebuggerEvent::ForcedReturn,
       
   366                            scriptId, lineNumber, columnNumber);
       
   367     e.setFileName(agent->scriptData(scriptId).fileName());
       
   368     e.setScriptValue(QScriptDebuggerValue(value));
       
   369     q->event(e);
       
   370 }
       
   371 
       
   372 /*!
       
   373   Creates a QScriptDebuggerBackend object.
       
   374 */
       
   375 QScriptDebuggerBackend::QScriptDebuggerBackend()
       
   376     : d_ptr(new QScriptDebuggerBackendPrivate)
       
   377 {
       
   378     d_ptr->q_ptr = this;
       
   379 }
       
   380 
       
   381 /*!
       
   382   Destroys this QScriptDebuggerBackend.
       
   383 */
       
   384 QScriptDebuggerBackend::~QScriptDebuggerBackend()
       
   385 {
       
   386     detach();
       
   387 }
       
   388 
       
   389 /*!
       
   390   \internal
       
   391 */
       
   392 QScriptDebuggerBackend::QScriptDebuggerBackend(QScriptDebuggerBackendPrivate &dd)
       
   393     : d_ptr(&dd)
       
   394 {
       
   395     d_ptr->q_ptr = this;
       
   396 }
       
   397 
       
   398 /*!
       
   399   Attaches this backend to the given \a engine.
       
   400   The backend automatically detaches from the old engine, if any.
       
   401 
       
   402   This function installs its own agent on the \a engine using
       
   403   QScriptEngine::setAgent(); any existing agent will be replaced.
       
   404 
       
   405   \sa detach(). engine()
       
   406 */
       
   407 void QScriptDebuggerBackend::attachTo(QScriptEngine *engine)
       
   408 {
       
   409     Q_D(QScriptDebuggerBackend);
       
   410     detach();
       
   411     d->agent = new QScriptDebuggerAgent(d, engine);
       
   412     QScriptValue global = engine->globalObject();
       
   413     d->origTraceFunction = global.property(QString::fromLatin1("print"));
       
   414     global.setProperty(QString::fromLatin1("print"), traceFunction());
       
   415 //    global.setProperty(QString::fromLatin1("qAssert"), assertFunction());
       
   416     d->origFileNameFunction = global.property(QString::fromLatin1("__FILE__"));
       
   417     global.setProperty(QString::fromLatin1("__FILE__"), fileNameFunction(),
       
   418                        QScriptValue::PropertyGetter | QScriptValue::ReadOnly);
       
   419     d->origLineNumberFunction = global.property(QString::fromLatin1("__LINE__"));
       
   420     global.setProperty(QString::fromLatin1("__LINE__"), lineNumberFunction(),
       
   421                        QScriptValue::PropertyGetter | QScriptValue::ReadOnly);
       
   422     engine->setAgent(d->agent);
       
   423 }
       
   424 
       
   425 /*!
       
   426   Detaches this backend from the current script engine.
       
   427   The backend's state (including breakpoints and information on loaded
       
   428   scripts) will be invalidated.
       
   429 
       
   430   \sa attach()
       
   431 */
       
   432 void QScriptDebuggerBackend::detach()
       
   433 {
       
   434     Q_D(QScriptDebuggerBackend);
       
   435     if (d->agent) {
       
   436         QScriptEngine *eng = d->agent->engine();
       
   437         if (eng && eng->agent() == d->agent) {
       
   438             eng->setAgent(0);
       
   439             QScriptValue global = eng->globalObject();
       
   440             global.setProperty(QString::fromLatin1("print"), d->origTraceFunction);
       
   441             d->origTraceFunction = QScriptValue();
       
   442 //            global.setProperty(QString::fromLatin1("qAssert"), QScriptValue());
       
   443             global.setProperty(QString::fromLatin1("__FILE__"), QScriptValue(),
       
   444                                QScriptValue::PropertyGetter);
       
   445             global.setProperty(QString::fromLatin1("__FILE__"), d->origFileNameFunction);
       
   446             d->origFileNameFunction = QScriptValue();
       
   447             global.setProperty(QString::fromLatin1("__LINE__"), QScriptValue(),
       
   448                                QScriptValue::PropertyGetter);
       
   449             global.setProperty(QString::fromLatin1("__LINE__"), d->origLineNumberFunction);
       
   450             d->origLineNumberFunction = QScriptValue();
       
   451             d->agent->nullifyBackendPointer();
       
   452             d->agent = 0; // agent is owned by engine
       
   453         }
       
   454     }
       
   455 
       
   456     d->pendingEvaluateLineNumber = -1;
       
   457     d->ignoreExceptions = false;
       
   458     d->nextScriptValueIteratorId = 0;
       
   459     qDeleteAll(d->scriptValueIterators);
       
   460     d->scriptValueIterators.clear();
       
   461     qDeleteAll(d->scriptObjectSnapshots);
       
   462     d->scriptObjectSnapshots.clear();
       
   463 }
       
   464 
       
   465 /*!
       
   466   Returns the script engine that this backend is attached to, or 0 if
       
   467   the backend is not attached to an engine.
       
   468 
       
   469   \sa attachTo()
       
   470 */
       
   471 QScriptEngine *QScriptDebuggerBackend::engine() const
       
   472 {
       
   473     Q_D(const QScriptDebuggerBackend);
       
   474     if (!d->agent)
       
   475         return 0;
       
   476     return d->agent->engine();
       
   477 }
       
   478 
       
   479 /*!
       
   480   Steps into the next script statement.
       
   481   When stepping is complete, an event() will be generated.
       
   482 */
       
   483 void QScriptDebuggerBackend::stepInto(int count)
       
   484 {
       
   485     Q_D(QScriptDebuggerBackend);
       
   486     if (d->agent) {
       
   487         d->agent->enterStepIntoMode(count);
       
   488         resume();
       
   489     }
       
   490 }
       
   491 
       
   492 /*!
       
   493   Steps over the next script statement.
       
   494   When stepping is complete, an event() will be generated.
       
   495 */
       
   496 void QScriptDebuggerBackend::stepOver(int count)
       
   497 {
       
   498     Q_D(QScriptDebuggerBackend);
       
   499     if (d->agent) {
       
   500         d->agent->enterStepOverMode(count);
       
   501         resume();
       
   502     }
       
   503 }
       
   504 
       
   505 /*!
       
   506   Steps out of the current script function.
       
   507   When stepping is complete, an event() will be generated.
       
   508 */
       
   509 void QScriptDebuggerBackend::stepOut()
       
   510 {
       
   511     Q_D(QScriptDebuggerBackend);
       
   512     if (d->agent) {
       
   513         d->agent->enterStepOutMode();
       
   514         resume();
       
   515     }
       
   516 }
       
   517 
       
   518 /*!
       
   519   Continues script evaluation. Evaluation will proceed without
       
   520   interruption until either 1) an uncaught exception occurs, 2) a
       
   521   breakpoint is triggered, or 3) interruptEvaluation() is called.
       
   522   In each case, a proper event() will be generated.
       
   523 */
       
   524 void QScriptDebuggerBackend::continueEvalution()
       
   525 {
       
   526     Q_D(QScriptDebuggerBackend);
       
   527     if (d->agent) {
       
   528         d->agent->enterContinueMode();
       
   529         resume();
       
   530     }
       
   531 }
       
   532 
       
   533 /*!
       
   534   Interrupts script evaluation. When the next script statement is
       
   535   reached, an event() will be generated.
       
   536 */
       
   537 void QScriptDebuggerBackend::interruptEvaluation()
       
   538 {
       
   539     Q_D(QScriptDebuggerBackend);
       
   540     if (d->agent)
       
   541         d->agent->enterInterruptMode();
       
   542 }
       
   543 
       
   544 /*!
       
   545   Continues evaluation until the location defined by the given \a
       
   546   fileName and \a lineNumber is reached. When the location is reached,
       
   547   an event() will be generated.
       
   548 */
       
   549 void QScriptDebuggerBackend::runToLocation(const QString &fileName, int lineNumber)
       
   550 {
       
   551     Q_D(QScriptDebuggerBackend);
       
   552     if (d->agent) {
       
   553         d->agent->enterRunToLocationMode(fileName, lineNumber);
       
   554         resume();
       
   555     }
       
   556 }
       
   557 
       
   558 /*!
       
   559   Continues evaluation until the location defined by the given \a
       
   560   scriptId and \a lineNumber is reached. When the location is reached,
       
   561   an event() will be generated.
       
   562 */
       
   563 void QScriptDebuggerBackend::runToLocation(qint64 scriptId, int lineNumber)
       
   564 {
       
   565     Q_D(QScriptDebuggerBackend);
       
   566     if (d->agent) {
       
   567         d->agent->enterRunToLocationMode(scriptId, lineNumber);
       
   568         resume();
       
   569     }
       
   570 }
       
   571 
       
   572 void QScriptDebuggerBackend::returnToCaller(int contextIndex, const QScriptValue &value)
       
   573 {
       
   574     Q_D(QScriptDebuggerBackend);
       
   575     if (d->agent) {
       
   576         d->agent->enterReturnByForceMode(contextIndex, value);
       
   577         resume();
       
   578     }
       
   579 }
       
   580 
       
   581 /*!
       
   582   Evaluates the given \a program. When evaluation is complete, an
       
   583   event() is generated.
       
   584 */
       
   585 void QScriptDebuggerBackend::evaluate(int contextIndex, const QString &program,
       
   586                                       const QString &fileName, int lineNumber)
       
   587 {
       
   588     Q_D(QScriptDebuggerBackend);
       
   589     d->pendingEvaluateContextIndex = contextIndex;
       
   590     d->pendingEvaluateProgram = program;
       
   591     d->pendingEvaluateFileName = fileName;
       
   592     d->pendingEvaluateLineNumber = lineNumber;
       
   593     if (!engine()->isEvaluating())
       
   594         doPendingEvaluate(/*postEvent=*/true);
       
   595     else
       
   596         resume();
       
   597 }
       
   598 
       
   599 /*!
       
   600   Executes the pending evaluate, if any.
       
   601 */
       
   602 void QScriptDebuggerBackend::doPendingEvaluate(bool postEvent)
       
   603 {
       
   604     Q_D(QScriptDebuggerBackend);
       
   605     QString program = d->pendingEvaluateProgram;
       
   606     if (program.isEmpty())
       
   607         return;
       
   608     int contextIndex = d->pendingEvaluateContextIndex;
       
   609     QScriptContext *ctx = context(contextIndex);
       
   610     Q_ASSERT(ctx != 0);
       
   611     QString fileName = d->pendingEvaluateFileName;
       
   612     int lineNumber = d->pendingEvaluateLineNumber;
       
   613     d->pendingEvaluateProgram = QString();
       
   614     d->pendingEvaluateFileName = QString();
       
   615     d->pendingEvaluateLineNumber = -1;
       
   616     d->pendingEvaluateContextIndex = -1;
       
   617 
       
   618     // push a new context and initialize its scope chain etc.
       
   619     {
       
   620         QScriptContext *evalContext = engine()->pushContext();
       
   621         QScriptValueList scopeChain = ctx->scopeChain();
       
   622         if (scopeChain.isEmpty())
       
   623             scopeChain.append(engine()->globalObject());
       
   624         while (!scopeChain.isEmpty())
       
   625             evalContext->pushScope(scopeChain.takeLast());
       
   626         evalContext->setActivationObject(ctx->activationObject());
       
   627         evalContext->setThisObject(ctx->thisObject());
       
   628     }
       
   629 
       
   630     d->agent->enterContinueMode();
       
   631     // set a flag so that any exception that happens in
       
   632     // the evaluate() is not sent to the debugger
       
   633     d->ignoreExceptions = true;
       
   634     bool hadException = engine()->hasUncaughtException();
       
   635     QScriptValue ret = engine()->evaluate(program, fileName, lineNumber);
       
   636     d->ignoreExceptions = false;
       
   637     if (!hadException && engine()->hasUncaughtException())
       
   638         engine()->clearExceptions();
       
   639     engine()->popContext();
       
   640 
       
   641     QScriptDebuggerValue retret(ret);
       
   642     QScriptDebuggerEvent e(QScriptDebuggerEvent::InlineEvalFinished);
       
   643     e.setScriptValue(retret);
       
   644     if (!ret.isUndefined())
       
   645         e.setMessage(ret.toString()); // for convenience -- we always need it
       
   646 
       
   647     e.setNestedEvaluate(engine()->isEvaluating());
       
   648 
       
   649     if (postEvent) {
       
   650         QScriptDebuggerEventEvent *de = new QScriptDebuggerEventEvent(e);
       
   651         d->postEvent(de);
       
   652     } else {
       
   653         event(e);
       
   654     }
       
   655 }
       
   656 
       
   657 /*!
       
   658   Sets a breakpoint defined by the given \a data, and returns a unique
       
   659   identifier for the new breakpoint.
       
   660 
       
   661   If the conditions of the breakpoint is satisfied at some point
       
   662   during script evaluation, a breakpoint event() will be generated.
       
   663 
       
   664   \sa deleteBreakpoint(), breakpoints()
       
   665 */
       
   666 int QScriptDebuggerBackend::setBreakpoint(const QScriptBreakpointData &data)
       
   667 {
       
   668     Q_D(QScriptDebuggerBackend);
       
   669     if (!d->agent)
       
   670         return -1;
       
   671     if (!data.isValid())
       
   672         return -1;
       
   673     return d->agent->setBreakpoint(data);
       
   674 }
       
   675 
       
   676 /*!
       
   677   Deletes the breakpoint identified by the given \a id.  Returns true
       
   678   if the breakpoint was deleted (i.e. the \a id was valid), otherwise
       
   679   returns false.
       
   680 
       
   681   \sa setBreakpoint()
       
   682 */
       
   683 bool QScriptDebuggerBackend::deleteBreakpoint(int id)
       
   684 {
       
   685     Q_D(QScriptDebuggerBackend);
       
   686     if (!d->agent)
       
   687         return false;
       
   688     return d->agent->deleteBreakpoint(id);
       
   689 }
       
   690 
       
   691 /*!
       
   692   Deletes all breakpoints.
       
   693 */
       
   694 void QScriptDebuggerBackend::deleteAllBreakpoints()
       
   695 {
       
   696     Q_D(QScriptDebuggerBackend);
       
   697     if (d->agent)
       
   698         d->agent->deleteAllBreakpoints();
       
   699 }
       
   700 
       
   701 /*!
       
   702   Returns the data associated with the breakpoint identified by the
       
   703   given \a id.
       
   704 */
       
   705 QScriptBreakpointData QScriptDebuggerBackend::breakpointData(int id) const
       
   706 {
       
   707     Q_D(const QScriptDebuggerBackend);
       
   708     if (!d->agent)
       
   709         return QScriptBreakpointData();
       
   710     return d->agent->breakpointData(id);
       
   711 }
       
   712 
       
   713 /*!
       
   714   Sets the \a data associated with the breakpoint identified by the
       
   715   given \a id.
       
   716 */
       
   717 bool QScriptDebuggerBackend::setBreakpointData(int id, const QScriptBreakpointData &data)
       
   718 {
       
   719     Q_D(QScriptDebuggerBackend);
       
   720     if (d->agent)
       
   721         return d->agent->setBreakpointData(id, data);
       
   722     return false;
       
   723 }
       
   724 
       
   725 /*!
       
   726   Returns this backend's breakpoints.
       
   727 
       
   728   \sa setBreakpoint()
       
   729 */
       
   730 QScriptBreakpointMap QScriptDebuggerBackend::breakpoints() const
       
   731 {
       
   732     Q_D(const QScriptDebuggerBackend);
       
   733     if (!d->agent)
       
   734         return QScriptBreakpointMap();
       
   735     return d->agent->breakpoints();
       
   736 }
       
   737 
       
   738 /*!
       
   739   Returns the scripts that this backend knows about.
       
   740 
       
   741   \sa scriptData()
       
   742 */
       
   743 QScriptScriptMap QScriptDebuggerBackend::scripts() const
       
   744 {
       
   745     Q_D(const QScriptDebuggerBackend);
       
   746     if (!d->agent)
       
   747         return QScriptScriptMap();
       
   748     return d->agent->scripts();
       
   749 }
       
   750 
       
   751 /*!
       
   752   Returns the data for the script identified by the given \a id.
       
   753 
       
   754   \sa scripts()
       
   755 */
       
   756 QScriptScriptData QScriptDebuggerBackend::scriptData(qint64 id) const
       
   757 {
       
   758     Q_D(const QScriptDebuggerBackend);
       
   759     if (!d->agent)
       
   760         return QScriptScriptData();
       
   761     return d->agent->scriptData(id);
       
   762 }
       
   763 
       
   764 /*!
       
   765   Makes a checkpoint of the currently loaded scripts.
       
   766 
       
   767   \sa scriptsDelta()
       
   768 */
       
   769 void QScriptDebuggerBackend::scriptsCheckpoint()
       
   770 {
       
   771     Q_D(QScriptDebuggerBackend);
       
   772     if (d->agent)
       
   773         d->agent->scriptsCheckpoint();
       
   774 }
       
   775 
       
   776 /*!
       
   777   Returns the difference between the latest scripts checkpoint and the
       
   778   previous checkpoint.  The first item in the pair is a list
       
   779   containing the identifiers of the scripts that were added. The
       
   780   second item in the pair is a list containing the identifiers of the
       
   781   scripts that were removed.
       
   782 
       
   783   \sa scriptsCheckpoint()
       
   784 */
       
   785 QScriptScriptsDelta QScriptDebuggerBackend::scriptsDelta() const
       
   786 {
       
   787     Q_D(const QScriptDebuggerBackend);
       
   788     if (!d->agent)
       
   789         return QPair<QList<qint64>, QList<qint64> >();
       
   790     return d->agent->scriptsDelta();
       
   791 }
       
   792 
       
   793 qint64 QScriptDebuggerBackend::resolveScript(const QString &fileName) const
       
   794 {
       
   795     Q_D(const QScriptDebuggerBackend);
       
   796     if (!d->agent)
       
   797         return -1;
       
   798     return d->agent->resolveScript(fileName);
       
   799 }
       
   800 
       
   801 /*!
       
   802   Returns the number of contexts (frames).
       
   803 */
       
   804 int QScriptDebuggerBackend::contextCount() const
       
   805 {
       
   806     if (!engine())
       
   807         return 0;
       
   808     return contextIds().count();
       
   809 }
       
   810 
       
   811 /*!
       
   812   Returns the context for the frame with the given \a index.
       
   813 */
       
   814 QScriptContext *QScriptDebuggerBackend::context(int index) const
       
   815 {
       
   816     if (index < 0)
       
   817         return 0;
       
   818     QScriptContext *ctx = engine()->currentContext();
       
   819     while (ctx) {
       
   820         if (index == 0)
       
   821             return ctx;
       
   822         ctx = ctx->parentContext();
       
   823         --index;
       
   824     }
       
   825     return 0;
       
   826 }
       
   827 
       
   828 /*!
       
   829   Returns a backtrace of the current execution.
       
   830 */
       
   831 QStringList QScriptDebuggerBackend::backtrace() const
       
   832 {
       
   833     if (!engine())
       
   834         return QStringList();
       
   835     return engine()->currentContext()->backtrace();
       
   836 }
       
   837 
       
   838 QList<qint64> QScriptDebuggerBackend::contextIds() const
       
   839 {
       
   840     Q_D(const QScriptDebuggerBackend);
       
   841     if (!d->agent)
       
   842         return QList<qint64>();
       
   843     return d->agent->contextIds();
       
   844 }
       
   845 
       
   846 QScriptContextsDelta QScriptDebuggerBackend::contextsCheckpoint()
       
   847 {
       
   848     Q_D(QScriptDebuggerBackend);
       
   849     if (!d->agent)
       
   850         return QScriptContextsDelta();
       
   851     return d->agent->contextsCheckpoint();
       
   852 }
       
   853 
       
   854 int QScriptDebuggerBackend::newScriptObjectSnapshot()
       
   855 {
       
   856     Q_D(QScriptDebuggerBackend);
       
   857     int id = d->nextScriptObjectSnapshotId;
       
   858     ++d->nextScriptObjectSnapshotId;
       
   859     d->scriptObjectSnapshots[id] = new QScriptObjectSnapshot();
       
   860     return id;
       
   861 }
       
   862 
       
   863 QScriptObjectSnapshot *QScriptDebuggerBackend::scriptObjectSnapshot(int id) const
       
   864 {
       
   865     Q_D(const QScriptDebuggerBackend);
       
   866     return d->scriptObjectSnapshots.value(id);
       
   867 }
       
   868 
       
   869 void QScriptDebuggerBackend::deleteScriptObjectSnapshot(int id)
       
   870 {
       
   871     Q_D(QScriptDebuggerBackend);
       
   872     QScriptObjectSnapshot *snap = d->scriptObjectSnapshots.take(id);
       
   873     delete snap;
       
   874 }
       
   875 
       
   876 int QScriptDebuggerBackend::newScriptValueIterator(const QScriptValue &object)
       
   877 {
       
   878     Q_D(QScriptDebuggerBackend);
       
   879     int id = d->nextScriptValueIteratorId;
       
   880     ++d->nextScriptValueIteratorId;
       
   881     d->scriptValueIterators[id] = new QScriptValueIterator(object);
       
   882     return id;
       
   883 }
       
   884 
       
   885 QScriptValueIterator *QScriptDebuggerBackend::scriptValueIterator(int id) const
       
   886 {
       
   887     Q_D(const QScriptDebuggerBackend);
       
   888     return d->scriptValueIterators.value(id);
       
   889 }
       
   890 
       
   891 void QScriptDebuggerBackend::deleteScriptValueIterator(int id)
       
   892 {
       
   893     Q_D(QScriptDebuggerBackend);
       
   894     QScriptValueIterator *it = d->scriptValueIterators.take(id);
       
   895     delete it;
       
   896 }
       
   897 
       
   898 bool QScriptDebuggerBackend::ignoreExceptions() const
       
   899 {
       
   900     Q_D(const QScriptDebuggerBackend);
       
   901     return d->ignoreExceptions;
       
   902 }
       
   903 
       
   904 void QScriptDebuggerBackend::setIgnoreExceptions(bool ignore)
       
   905 {
       
   906     Q_D(QScriptDebuggerBackend);
       
   907     d->ignoreExceptions = ignore;
       
   908 }
       
   909 
       
   910 /*!
       
   911   Returns a trace function. The trace function has similar semantics
       
   912   to the built-in print() function; however, instead of writing text
       
   913   to standard output, it generates a trace event containing the text.
       
   914 */
       
   915 QScriptValue QScriptDebuggerBackend::traceFunction() const
       
   916 {
       
   917     Q_D(const QScriptDebuggerBackend);
       
   918     if (!engine())
       
   919         return QScriptValue();
       
   920     QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::trace);
       
   921     fun.setData(qScriptValueFromValue(engine(), const_cast<QScriptDebuggerBackendPrivate*>(d)));
       
   922     return fun;
       
   923 }
       
   924 
       
   925 QScriptValue QScriptDebuggerBackend::assertFunction() const
       
   926 {
       
   927     if (!engine())
       
   928         return QScriptValue();
       
   929     QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::qsassert);
       
   930     return fun;
       
   931 }
       
   932 
       
   933 QScriptValue QScriptDebuggerBackend::fileNameFunction() const
       
   934 {
       
   935     if (!engine())
       
   936         return QScriptValue();
       
   937     QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::fileName);
       
   938     return fun;
       
   939 }
       
   940 
       
   941 QScriptValue QScriptDebuggerBackend::lineNumberFunction() const
       
   942 {
       
   943     if (!engine())
       
   944         return QScriptValue();
       
   945     QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::lineNumber);
       
   946     return fun;
       
   947 }
       
   948 
       
   949 QScriptDebuggerCommandExecutor *QScriptDebuggerBackend::commandExecutor() const
       
   950 {
       
   951     Q_D(const QScriptDebuggerBackend);
       
   952     if (d->commandExecutor)
       
   953         return d->commandExecutor;
       
   954     QScriptDebuggerBackendPrivate *dd = const_cast<QScriptDebuggerBackendPrivate*>(d);
       
   955     dd->commandExecutor = new QScriptDebuggerCommandExecutor();
       
   956     return dd->commandExecutor;
       
   957 }
       
   958 
       
   959 void QScriptDebuggerBackend::setCommandExecutor(QScriptDebuggerCommandExecutor *executor)
       
   960 {
       
   961     Q_D(QScriptDebuggerBackend);
       
   962     d->commandExecutor = executor;
       
   963 }
       
   964 
       
   965 /*!
       
   966   \fn void QScriptDebuggerBackend::resume()
       
   967 
       
   968   This function is called when control should be returned back to the
       
   969   back-end, i.e. when script evaluation should be resumed after an
       
   970   event has been delivered.
       
   971 
       
   972   Subclasses must reimplement this function to make event() return.
       
   973 
       
   974   \sa event()
       
   975 */
       
   976 
       
   977 /*!
       
   978   \fn void QScriptDebuggerBackend::event(const QScriptDebuggerEvent &event)
       
   979 
       
   980   This function is called when the back-end has generated the given \a event.
       
   981 
       
   982   Subclasses must reimplement this function to handle the
       
   983   event. Typically the event is forwarded to a
       
   984   QScriptDebuggerFrontend, which will in turn forward it to its
       
   985   QScriptDebuggerClient. The client may then query the front-end for
       
   986   information about the execution state, and call e.g.
       
   987   continueEvalution() to resume execution. This function should block
       
   988   until resume() is called.
       
   989 
       
   990   \sa resume()
       
   991 */
       
   992 
       
   993 QT_END_NAMESPACE