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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 30.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtSCriptTools module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia 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 : 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
143QScriptDebuggerBackendPrivate::~QScriptDebuggerBackendPrivate()
144{
145 if (agent)
146 agent->nullifyBackendPointer();
147 delete commandExecutor;
148 delete eventReceiver;
149 qDeleteAll(scriptValueIterators);
150 qDeleteAll(scriptObjectSnapshots);
151}
152
153void 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
162bool 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
172void 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*/
185void 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*/
205void 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*/
219void 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*/
233void 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*/
250void 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
284QScriptValue 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
303QScriptValue 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
329QScriptValue 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
339QScriptValue 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*/
350void 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
360void 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*/
375QScriptDebuggerBackend::QScriptDebuggerBackend()
376 : d_ptr(new QScriptDebuggerBackendPrivate)
377{
378 d_ptr->q_ptr = this;
379}
380
381/*!
382 Destroys this QScriptDebuggerBackend.
383*/
384QScriptDebuggerBackend::~QScriptDebuggerBackend()
385{
386 detach();
387}
388
389/*!
390 \internal
391*/
392QScriptDebuggerBackend::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*/
407void 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*/
432void 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*/
471QScriptEngine *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*/
483void 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*/
496void 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*/
509void 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*/
524void 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*/
537void 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*/
549void 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*/
563void 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
572void 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*/
585void 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*/
602void 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*/
666int 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*/
683bool 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*/
694void 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*/
705QScriptBreakpointData 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*/
717bool 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*/
730QScriptBreakpointMap 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*/
743QScriptScriptMap 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*/
756QScriptScriptData 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*/
769void 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*/
785QScriptScriptsDelta 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
793qint64 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*/
804int 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*/
814QScriptContext *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*/
831QStringList QScriptDebuggerBackend::backtrace() const
832{
833 if (!engine())
834 return QStringList();
835 return engine()->currentContext()->backtrace();
836}
837
838QList<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
846QScriptContextsDelta QScriptDebuggerBackend::contextsCheckpoint()
847{
848 Q_D(QScriptDebuggerBackend);
849 if (!d->agent)
850 return QScriptContextsDelta();
851 return d->agent->contextsCheckpoint();
852}
853
854int 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
863QScriptObjectSnapshot *QScriptDebuggerBackend::scriptObjectSnapshot(int id) const
864{
865 Q_D(const QScriptDebuggerBackend);
866 return d->scriptObjectSnapshots.value(id);
867}
868
869void QScriptDebuggerBackend::deleteScriptObjectSnapshot(int id)
870{
871 Q_D(QScriptDebuggerBackend);
872 QScriptObjectSnapshot *snap = d->scriptObjectSnapshots.take(id);
873 delete snap;
874}
875
876int 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
885QScriptValueIterator *QScriptDebuggerBackend::scriptValueIterator(int id) const
886{
887 Q_D(const QScriptDebuggerBackend);
888 return d->scriptValueIterators.value(id);
889}
890
891void QScriptDebuggerBackend::deleteScriptValueIterator(int id)
892{
893 Q_D(QScriptDebuggerBackend);
894 QScriptValueIterator *it = d->scriptValueIterators.take(id);
895 delete it;
896}
897
898bool QScriptDebuggerBackend::ignoreExceptions() const
899{
900 Q_D(const QScriptDebuggerBackend);
901 return d->ignoreExceptions;
902}
903
904void 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*/
915QScriptValue 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
925QScriptValue QScriptDebuggerBackend::assertFunction() const
926{
927 if (!engine())
928 return QScriptValue();
929 QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::qsassert);
930 return fun;
931}
932
933QScriptValue QScriptDebuggerBackend::fileNameFunction() const
934{
935 if (!engine())
936 return QScriptValue();
937 QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::fileName);
938 return fun;
939}
940
941QScriptValue QScriptDebuggerBackend::lineNumberFunction() const
942{
943 if (!engine())
944 return QScriptValue();
945 QScriptValue fun = engine()->newFunction(QScriptDebuggerBackendPrivate::lineNumber);
946 return fun;
947}
948
949QScriptDebuggerCommandExecutor *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
959void 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
993QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.