source: trunk/src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp@ 715

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

trunk: Merged in qt 4.6.2 sources.

File size: 19.2 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 "qscriptdebuggercommandexecutor_p.h"
43
44#include "qscriptdebuggerbackend_p.h"
45#include "qscriptdebuggercommand_p.h"
46#include "qscriptdebuggerresponse_p.h"
47#include "qscriptdebuggervalue_p.h"
48#include "qscriptdebuggervalueproperty_p.h"
49#include "qscriptbreakpointdata_p.h"
50#include "qscriptobjectsnapshot_p.h"
51#include "qscriptdebuggerobjectsnapshotdelta_p.h"
52
53#include <QtCore/qstringlist.h>
54#include <QtScript/qscriptengine.h>
55#include <QtScript/qscriptcontextinfo.h>
56#include <QtScript/qscriptvalueiterator.h>
57#include <QtCore/qdebug.h>
58
59Q_DECLARE_METATYPE(QScriptScriptsDelta)
60Q_DECLARE_METATYPE(QScriptDebuggerValueProperty)
61Q_DECLARE_METATYPE(QScriptDebuggerValuePropertyList)
62Q_DECLARE_METATYPE(QScriptDebuggerObjectSnapshotDelta)
63
64QT_BEGIN_NAMESPACE
65
66/*!
67 \since 4.5
68 \class QScriptDebuggerCommandExecutor
69 \internal
70
71 \brief The QScriptDebuggerCommandExecutor applies debugger commands to a back-end.
72
73 The execute() function takes a command (typically produced by a
74 QScriptDebuggerFrontend) and applies it to a QScriptDebuggerBackend.
75
76 \sa QScriptDebuggerCommmand
77*/
78
79class QScriptDebuggerCommandExecutorPrivate
80{
81public:
82 QScriptDebuggerCommandExecutorPrivate();
83 ~QScriptDebuggerCommandExecutorPrivate();
84};
85
86QScriptDebuggerCommandExecutorPrivate::QScriptDebuggerCommandExecutorPrivate()
87{
88}
89
90QScriptDebuggerCommandExecutorPrivate::~QScriptDebuggerCommandExecutorPrivate()
91{
92}
93
94QScriptDebuggerCommandExecutor::QScriptDebuggerCommandExecutor()
95 : d_ptr(new QScriptDebuggerCommandExecutorPrivate())
96{
97}
98
99QScriptDebuggerCommandExecutor::~QScriptDebuggerCommandExecutor()
100{
101}
102
103static bool isPrefixOf(const QString &prefix, const QString &what)
104{
105 return ((what.length() > prefix.length())
106 && what.startsWith(prefix));
107}
108
109/*!
110 Applies the given \a command to the given \a backend.
111*/
112QScriptDebuggerResponse QScriptDebuggerCommandExecutor::execute(
113 QScriptDebuggerBackend *backend,
114 const QScriptDebuggerCommand &command)
115{
116 QScriptDebuggerResponse response;
117 switch (command.type()) {
118 case QScriptDebuggerCommand::None:
119 break;
120
121 case QScriptDebuggerCommand::Interrupt:
122 backend->interruptEvaluation();
123 break;
124
125 case QScriptDebuggerCommand::Continue:
126 if (backend->engine()->isEvaluating()) {
127 backend->continueEvalution();
128 response.setAsync(true);
129 }
130 break;
131
132 case QScriptDebuggerCommand::StepInto: {
133 QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount);
134 int count = attr.isValid() ? attr.toInt() : 1;
135 backend->stepInto(count);
136 response.setAsync(true);
137 } break;
138
139 case QScriptDebuggerCommand::StepOver: {
140 QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount);
141 int count = attr.isValid() ? attr.toInt() : 1;
142 backend->stepOver(count);
143 response.setAsync(true);
144 } break;
145
146 case QScriptDebuggerCommand::StepOut:
147 backend->stepOut();
148 response.setAsync(true);
149 break;
150
151 case QScriptDebuggerCommand::RunToLocation:
152 backend->runToLocation(command.fileName(), command.lineNumber());
153 response.setAsync(true);
154 break;
155
156 case QScriptDebuggerCommand::RunToLocationByID:
157 backend->runToLocation(command.scriptId(), command.lineNumber());
158 response.setAsync(true);
159 break;
160
161 case QScriptDebuggerCommand::ForceReturn: {
162 int contextIndex = command.contextIndex();
163 QScriptDebuggerValue value = command.scriptValue();
164 QScriptEngine *engine = backend->engine();
165 QScriptValue realValue = value.toScriptValue(engine);
166 backend->returnToCaller(contextIndex, realValue);
167 response.setAsync(true);
168 } break;
169
170 case QScriptDebuggerCommand::Resume:
171 backend->resume();
172 response.setAsync(true);
173 break;
174
175 case QScriptDebuggerCommand::SetBreakpoint: {
176 QScriptBreakpointData data = command.breakpointData();
177 if (!data.isValid())
178 data = QScriptBreakpointData(command.fileName(), command.lineNumber());
179 int id = backend->setBreakpoint(data);
180 response.setResult(id);
181 } break;
182
183 case QScriptDebuggerCommand::DeleteBreakpoint: {
184 int id = command.breakpointId();
185 if (!backend->deleteBreakpoint(id))
186 response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
187 } break;
188
189 case QScriptDebuggerCommand::DeleteAllBreakpoints:
190 backend->deleteAllBreakpoints();
191 break;
192
193 case QScriptDebuggerCommand::GetBreakpoints: {
194 QScriptBreakpointMap bps = backend->breakpoints();
195 if (!bps.isEmpty())
196 response.setResult(bps);
197 } break;
198
199 case QScriptDebuggerCommand::GetBreakpointData: {
200 int id = command.breakpointId();
201 QScriptBreakpointData data = backend->breakpointData(id);
202 if (data.isValid())
203 response.setResult(data);
204 else
205 response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
206 } break;
207
208 case QScriptDebuggerCommand::SetBreakpointData: {
209 int id = command.breakpointId();
210 QScriptBreakpointData data = command.breakpointData();
211 if (!backend->setBreakpointData(id, data))
212 response.setError(QScriptDebuggerResponse::InvalidBreakpointID);
213 } break;
214
215 case QScriptDebuggerCommand::GetScripts: {
216 QScriptScriptMap scripts = backend->scripts();
217 if (!scripts.isEmpty())
218 response.setResult(scripts);
219 } break;
220
221 case QScriptDebuggerCommand::GetScriptData: {
222 qint64 id = command.scriptId();
223 QScriptScriptData data = backend->scriptData(id);
224 if (data.isValid())
225 response.setResult(data);
226 else
227 response.setError(QScriptDebuggerResponse::InvalidScriptID);
228 } break;
229
230 case QScriptDebuggerCommand::ScriptsCheckpoint:
231 backend->scriptsCheckpoint();
232 response.setResult(qVariantFromValue(backend->scriptsDelta()));
233 break;
234
235 case QScriptDebuggerCommand::GetScriptsDelta:
236 response.setResult(qVariantFromValue(backend->scriptsDelta()));
237 break;
238
239 case QScriptDebuggerCommand::ResolveScript:
240 response.setResult(backend->resolveScript(command.fileName()));
241 break;
242
243 case QScriptDebuggerCommand::GetBacktrace:
244 response.setResult(backend->backtrace());
245 break;
246
247 case QScriptDebuggerCommand::GetContextCount:
248 response.setResult(backend->contextCount());
249 break;
250
251 case QScriptDebuggerCommand::GetContextState: {
252 QScriptContext *ctx = backend->context(command.contextIndex());
253 if (ctx)
254 response.setResult(static_cast<int>(ctx->state()));
255 else
256 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
257 } break;
258
259 case QScriptDebuggerCommand::GetContextID: {
260 int idx = command.contextIndex();
261 if ((idx >= 0) && (idx < backend->contextCount()))
262 response.setResult(backend->contextIds()[idx]);
263 else
264 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
265 } break;
266
267 case QScriptDebuggerCommand::GetContextInfo: {
268 QScriptContext *ctx = backend->context(command.contextIndex());
269 if (ctx)
270 response.setResult(QScriptContextInfo(ctx));
271 else
272 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
273 } break;
274
275 case QScriptDebuggerCommand::GetThisObject: {
276 QScriptContext *ctx = backend->context(command.contextIndex());
277 if (ctx)
278 response.setResult(ctx->thisObject());
279 else
280 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
281 } break;
282
283 case QScriptDebuggerCommand::GetActivationObject: {
284 QScriptContext *ctx = backend->context(command.contextIndex());
285 if (ctx)
286 response.setResult(ctx->activationObject());
287 else
288 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
289 } break;
290
291 case QScriptDebuggerCommand::GetScopeChain: {
292 QScriptContext *ctx = backend->context(command.contextIndex());
293 if (ctx) {
294 QScriptDebuggerValueList dest;
295 QScriptValueList src = ctx->scopeChain();
296 for (int i = 0; i < src.size(); ++i)
297 dest.append(src.at(i));
298 response.setResult(dest);
299 } else {
300 response.setError(QScriptDebuggerResponse::InvalidContextIndex);
301 }
302 } break;
303
304 case QScriptDebuggerCommand::ContextsCheckpoint: {
305 response.setResult(qVariantFromValue(backend->contextsCheckpoint()));
306 } break;
307
308 case QScriptDebuggerCommand::GetPropertyExpressionValue: {
309 QScriptContext *ctx = backend->context(command.contextIndex());
310 int lineNumber = command.lineNumber();
311 QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute);
312 QStringList path = attr.toStringList();
313 if (!ctx || path.isEmpty())
314 break;
315 QScriptContextInfo ctxInfo(ctx);
316 if (ctx->callee().isValid()
317 && ((lineNumber < ctxInfo.functionStartLineNumber())
318 || (lineNumber > ctxInfo.functionEndLineNumber()))) {
319 break;
320 }
321 QScriptValueList objects;
322 int pathIndex = 0;
323 if (path.at(0) == QLatin1String("this")) {
324 objects.append(ctx->thisObject());
325 ++pathIndex;
326 } else {
327 objects << ctx->scopeChain();
328 }
329 for (int i = 0; i < objects.size(); ++i) {
330 QScriptValue val = objects.at(i);
331 for (int j = pathIndex; val.isValid() && (j < path.size()); ++j) {
332 val = val.property(path.at(j));
333 }
334 if (val.isValid()) {
335 bool hadException = (ctx->state() == QScriptContext::ExceptionState);
336 QString str = val.toString();
337 if (!hadException && backend->engine()->hasUncaughtException())
338 backend->engine()->clearExceptions();
339 response.setResult(str);
340 break;
341 }
342 }
343 } break;
344
345 case QScriptDebuggerCommand::GetCompletions: {
346 QScriptContext *ctx = backend->context(command.contextIndex());
347 QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute);
348 QStringList path = attr.toStringList();
349 if (!ctx || path.isEmpty())
350 break;
351 QScriptValueList objects;
352 QString prefix = path.last();
353 QSet<QString> matches;
354 if (path.size() > 1) {
355 const QString &topLevelIdent = path.at(0);
356 QScriptValue obj;
357 if (topLevelIdent == QLatin1String("this")) {
358 obj = ctx->thisObject();
359 } else {
360 QScriptValueList scopeChain;
361 scopeChain = ctx->scopeChain();
362 for (int i = 0; i < scopeChain.size(); ++i) {
363 QScriptValue oo = scopeChain.at(i).property(topLevelIdent);
364 if (oo.isObject()) {
365 obj = oo;
366 break;
367 }
368 }
369 }
370 for (int i = 1; obj.isObject() && (i < path.size()-1); ++i)
371 obj = obj.property(path.at(i));
372 if (obj.isValid())
373 objects.append(obj);
374 } else {
375 objects << ctx->scopeChain();
376 QStringList keywords;
377 keywords.append(QString::fromLatin1("this"));
378 keywords.append(QString::fromLatin1("true"));
379 keywords.append(QString::fromLatin1("false"));
380 keywords.append(QString::fromLatin1("null"));
381 for (int i = 0; i < keywords.size(); ++i) {
382 const QString &kwd = keywords.at(i);
383 if (isPrefixOf(prefix, kwd))
384 matches.insert(kwd);
385 }
386 }
387
388 for (int i = 0; i < objects.size(); ++i) {
389 QScriptValue obj = objects.at(i);
390 while (obj.isObject()) {
391 QScriptValueIterator it(obj);
392 while (it.hasNext()) {
393 it.next();
394 QString propertyName = it.name();
395 if (isPrefixOf(prefix, propertyName))
396 matches.insert(propertyName);
397 }
398 obj = obj.prototype();
399 }
400 }
401 QStringList matchesList = matches.toList();
402 qStableSort(matchesList);
403 response.setResult(matchesList);
404 } break;
405
406 case QScriptDebuggerCommand::NewScriptObjectSnapshot: {
407 int id = backend->newScriptObjectSnapshot();
408 response.setResult(id);
409 } break;
410
411 case QScriptDebuggerCommand::ScriptObjectSnapshotCapture: {
412 int id = command.snapshotId();
413 QScriptObjectSnapshot *snap = backend->scriptObjectSnapshot(id);
414 Q_ASSERT(snap != 0);
415 QScriptDebuggerValue object = command.scriptValue();
416 Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
417 QScriptEngine *engine = backend->engine();
418 QScriptValue realObject = object.toScriptValue(engine);
419 Q_ASSERT(realObject.isObject());
420 QScriptObjectSnapshot::Delta delta = snap->capture(realObject);
421 QScriptDebuggerObjectSnapshotDelta result;
422 result.removedProperties = delta.removedProperties;
423 bool didIgnoreExceptions = backend->ignoreExceptions();
424 backend->setIgnoreExceptions(true);
425 for (int i = 0; i < delta.changedProperties.size(); ++i) {
426 const QScriptValueProperty &src = delta.changedProperties.at(i);
427 bool hadException = engine->hasUncaughtException();
428 QString str = src.value().toString();
429 if (!hadException && engine->hasUncaughtException())
430 engine->clearExceptions();
431 QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags());
432 result.changedProperties.append(dest);
433 }
434 for (int j = 0; j < delta.addedProperties.size(); ++j) {
435 const QScriptValueProperty &src = delta.addedProperties.at(j);
436 bool hadException = engine->hasUncaughtException();
437 QString str = src.value().toString();
438 if (!hadException && engine->hasUncaughtException())
439 engine->clearExceptions();
440 QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags());
441 result.addedProperties.append(dest);
442 }
443 backend->setIgnoreExceptions(didIgnoreExceptions);
444 response.setResult(qVariantFromValue(result));
445 } break;
446
447 case QScriptDebuggerCommand::DeleteScriptObjectSnapshot: {
448 int id = command.snapshotId();
449 backend->deleteScriptObjectSnapshot(id);
450 } break;
451
452 case QScriptDebuggerCommand::NewScriptValueIterator: {
453 QScriptDebuggerValue object = command.scriptValue();
454 Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
455 QScriptEngine *engine = backend->engine();
456 QScriptValue realObject = object.toScriptValue(engine);
457 Q_ASSERT(realObject.isObject());
458 int id = backend->newScriptValueIterator(realObject);
459 response.setResult(id);
460 } break;
461
462 case QScriptDebuggerCommand::GetPropertiesByIterator: {
463 int id = command.iteratorId();
464 int count = 1000;
465 QScriptValueIterator *it = backend->scriptValueIterator(id);
466 Q_ASSERT(it != 0);
467 QScriptDebuggerValuePropertyList props;
468 for (int i = 0; (i < count) && it->hasNext(); ++i) {
469 it->next();
470 QString name = it->name();
471 QScriptValue value = it->value();
472 QString valueAsString = value.toString();
473 QScriptValue::PropertyFlags flags = it->flags();
474 QScriptDebuggerValueProperty prp(name, value, valueAsString, flags);
475 props.append(prp);
476 }
477 response.setResult(props);
478 } break;
479
480 case QScriptDebuggerCommand::DeleteScriptValueIterator: {
481 int id = command.iteratorId();
482 backend->deleteScriptValueIterator(id);
483 } break;
484
485 case QScriptDebuggerCommand::Evaluate: {
486 int contextIndex = command.contextIndex();
487 QString program = command.program();
488 QString fileName = command.fileName();
489 int lineNumber = command.lineNumber();
490 backend->evaluate(contextIndex, program, fileName, lineNumber);
491 response.setAsync(true);
492 } break;
493
494 case QScriptDebuggerCommand::ScriptValueToString: {
495 QScriptDebuggerValue value = command.scriptValue();
496 QScriptEngine *engine = backend->engine();
497 QScriptValue realValue = value.toScriptValue(engine);
498 response.setResult(realValue.toString());
499 } break;
500
501 case QScriptDebuggerCommand::SetScriptValueProperty: {
502 QScriptDebuggerValue object = command.scriptValue();
503 QScriptEngine *engine = backend->engine();
504 QScriptValue realObject = object.toScriptValue(engine);
505 QScriptDebuggerValue value = command.subordinateScriptValue();
506 QScriptValue realValue = value.toScriptValue(engine);
507 QString name = command.name();
508 realObject.setProperty(name, realValue);
509 } break;
510
511 case QScriptDebuggerCommand::ClearExceptions:
512 backend->engine()->clearExceptions();
513 break;
514
515 case QScriptDebuggerCommand::UserCommand:
516 case QScriptDebuggerCommand::MaxUserCommand:
517 break;
518 }
519 return response;
520}
521
522QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.