| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2018 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the QtSCriptTools module of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU Lesser General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| 21 | ** packaging of this file. Please review the following information to |
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements |
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| 24 | ** |
| 25 | ** GNU General Public License Usage |
| 26 | ** Alternatively, this file may be used under the terms of the GNU |
| 27 | ** General Public License version 2.0 or (at your option) the GNU General |
| 28 | ** Public license version 3 or any later version approved by the KDE Free |
| 29 | ** Qt Foundation. The licenses are as published by the Free Software |
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| 31 | ** included in the packaging of this file. Please review the following |
| 32 | ** information to ensure the GNU General Public License requirements will |
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
| 35 | ** |
| 36 | ** $QT_END_LICENSE$ |
| 37 | ** |
| 38 | ****************************************************************************/ |
| 39 | |
| 40 | #include "qscriptdebuggercommandexecutor_p.h" |
| 41 | |
| 42 | #include "qscriptdebuggerbackend_p.h" |
| 43 | #include "qscriptdebuggercommand_p.h" |
| 44 | #include "qscriptdebuggerresponse_p.h" |
| 45 | #include "qscriptdebuggervalue_p.h" |
| 46 | #include "qscriptdebuggervalueproperty_p.h" |
| 47 | #include "qscriptbreakpointdata_p.h" |
| 48 | #include "qscriptobjectsnapshot_p.h" |
| 49 | #include "qscriptdebuggerobjectsnapshotdelta_p.h" |
| 50 | |
| 51 | #include <QtCore/qstringlist.h> |
| 52 | #include <QtScript/qscriptengine.h> |
| 53 | #include <QtScript/qscriptcontextinfo.h> |
| 54 | #include <QtScript/qscriptvalueiterator.h> |
| 55 | #include <QtCore/qdebug.h> |
| 56 | |
| 57 | #include <algorithm> |
| 58 | |
| 59 | Q_DECLARE_METATYPE(QScriptScriptsDelta) |
| 60 | Q_DECLARE_METATYPE(QScriptDebuggerValueProperty) |
| 61 | Q_DECLARE_METATYPE(QScriptDebuggerValuePropertyList) |
| 62 | Q_DECLARE_METATYPE(QScriptDebuggerObjectSnapshotDelta) |
| 63 | |
| 64 | QT_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 | |
| 79 | class QScriptDebuggerCommandExecutorPrivate |
| 80 | { |
| 81 | public: |
| 82 | QScriptDebuggerCommandExecutorPrivate(); |
| 83 | ~QScriptDebuggerCommandExecutorPrivate(); |
| 84 | }; |
| 85 | |
| 86 | QScriptDebuggerCommandExecutorPrivate::QScriptDebuggerCommandExecutorPrivate() |
| 87 | { |
| 88 | } |
| 89 | |
| 90 | QScriptDebuggerCommandExecutorPrivate::~QScriptDebuggerCommandExecutorPrivate() |
| 91 | { |
| 92 | } |
| 93 | |
| 94 | QScriptDebuggerCommandExecutor::QScriptDebuggerCommandExecutor() |
| 95 | : d_ptr(new QScriptDebuggerCommandExecutorPrivate()) |
| 96 | { |
| 97 | } |
| 98 | |
| 99 | QScriptDebuggerCommandExecutor::~QScriptDebuggerCommandExecutor() |
| 100 | { |
| 101 | } |
| 102 | |
| 103 | static bool isPrefixOf(const QString &prefix, const QString &what) |
| 104 | { |
| 105 | return ((what.length() > prefix.length()) |
| 106 | && what.startsWith(s: prefix)); |
| 107 | } |
| 108 | |
| 109 | /*! |
| 110 | Applies the given \a command to the given \a backend. |
| 111 | */ |
| 112 | QScriptDebuggerResponse 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(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(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(fileName: command.fileName(), lineNumber: command.lineNumber()); |
| 153 | response.setAsync(true); |
| 154 | break; |
| 155 | |
| 156 | case QScriptDebuggerCommand::RunToLocationByID: |
| 157 | backend->runToLocation(scriptId: command.scriptId(), lineNumber: 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, value: 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(QVariant::fromValue(value: backend->scriptsDelta())); |
| 233 | break; |
| 234 | |
| 235 | case QScriptDebuggerCommand::GetScriptsDelta: |
| 236 | response.setResult(QVariant::fromValue(value: backend->scriptsDelta())); |
| 237 | break; |
| 238 | |
| 239 | case QScriptDebuggerCommand::ResolveScript: |
| 240 | response.setResult(backend->resolveScript(fileName: 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(index: 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(index: 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(index: 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(index: 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(index: 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(t: 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(QVariant::fromValue(value: backend->contextsCheckpoint())); |
| 306 | } break; |
| 307 | |
| 308 | case QScriptDebuggerCommand::GetPropertyExpressionValue: { |
| 309 | QScriptContext *ctx = backend->context(index: command.contextIndex()); |
| 310 | int lineNumber = command.lineNumber(); |
| 311 | QVariant attr = command.attribute(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(i: 0) == QLatin1String("this" )) { |
| 324 | objects.append(t: 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(name: path.at(i: 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(index: command.contextIndex()); |
| 347 | QVariant attr = command.attribute(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(i: 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(name: 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(name: path.at(i)); |
| 372 | if (obj.isValid()) |
| 373 | objects.append(t: obj); |
| 374 | } else { |
| 375 | objects << ctx->scopeChain(); |
| 376 | QStringList keywords; |
| 377 | keywords.append(t: QString::fromLatin1(str: "this" )); |
| 378 | keywords.append(t: QString::fromLatin1(str: "true" )); |
| 379 | keywords.append(t: QString::fromLatin1(str: "false" )); |
| 380 | keywords.append(t: QString::fromLatin1(str: "null" )); |
| 381 | for (int i = 0; i < keywords.size(); ++i) { |
| 382 | const QString &kwd = keywords.at(i); |
| 383 | if (isPrefixOf(prefix, what: kwd)) |
| 384 | matches.insert(value: 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, what: propertyName)) |
| 396 | matches.insert(value: propertyName); |
| 397 | } |
| 398 | obj = obj.prototype(); |
| 399 | } |
| 400 | } |
| 401 | QStringList matchesList = matches.toList(); |
| 402 | std::stable_sort(first: matchesList.begin(), last: matchesList.end()); |
| 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(object: 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(t: dest); |
| 433 | } |
| 434 | for (int j = 0; j < delta.addedProperties.size(); ++j) { |
| 435 | const QScriptValueProperty &src = delta.addedProperties.at(i: 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(t: dest); |
| 442 | } |
| 443 | backend->setIgnoreExceptions(didIgnoreExceptions); |
| 444 | response.setResult(QVariant::fromValue(value: 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(object: 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(t: 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, value: 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 | |
| 522 | QT_END_NAMESPACE |
| 523 | |