source: trunk/src/scripttools/debugging/qscriptdebuggerbackend.cpp@ 160

Last change on this file since 160 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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