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 "qscriptdebuggerscriptedconsolecommand_p.h"
41#include "qscriptdebuggerconsolecommand_p_p.h"
42#include "qscriptdebuggerconsolecommandjob_p.h"
43#include "qscriptdebuggerconsolecommandjob_p_p.h"
44#include "qscriptmessagehandlerinterface_p.h"
45#include "qscriptdebuggerconsoleglobalobject_p.h"
46#include "qscriptdebuggerresponse_p.h"
47#include "qscriptdebuggercommandschedulerinterface_p.h"
48
49#include <QtCore/qstring.h>
50#include <QtCore/qstringlist.h>
51#include <QtScript/qscriptengine.h>
52#include <QtScript/qscriptvalue.h>
53#include <QtScript/qscriptvalueiterator.h>
54#include <QtScript/qscriptcontextinfo.h>
55#include <QtCore/qdebug.h>
56
57Q_DECLARE_METATYPE(QScriptDebuggerResponse)
58
59QT_BEGIN_NAMESPACE
60
61/*!
62 \since 4.5
63 \class QScriptDebuggerScriptedConsoleCommand
64 \internal
65
66 \brief The QScriptDebuggerScriptedConsoleCommand class encapsulates a command defined in a script.
67*/
68
69class QScriptDebuggerScriptedConsoleCommandPrivate
70 : public QScriptDebuggerConsoleCommandPrivate
71{
72 Q_DECLARE_PUBLIC(QScriptDebuggerScriptedConsoleCommand)
73public:
74 QScriptDebuggerScriptedConsoleCommandPrivate();
75 ~QScriptDebuggerScriptedConsoleCommandPrivate();
76
77 QString name;
78 QString group;
79 QString shortDescription;
80 QString longDescription;
81 QStringList aliases;
82 QStringList seeAlso;
83 QStringList argumentTypes;
84 QStringList subCommands;
85 QScriptValue globalObject;
86 QScriptValue execFunction;
87 QScriptValue responseFunction;
88};
89
90QScriptDebuggerScriptedConsoleCommandPrivate::QScriptDebuggerScriptedConsoleCommandPrivate()
91{
92}
93
94QScriptDebuggerScriptedConsoleCommandPrivate::~QScriptDebuggerScriptedConsoleCommandPrivate()
95{
96}
97
98QScriptDebuggerScriptedConsoleCommand::QScriptDebuggerScriptedConsoleCommand(
99 const QString &name, const QString &group,
100 const QString &shortDescription, const QString &longDescription,
101 const QStringList &aliases, const QStringList &seeAlso,
102 const QStringList &argumentTypes, const QStringList &subCommands,
103 const QScriptValue &globalObject,
104 const QScriptValue &execFunction, const QScriptValue &responseFunction)
105 : QScriptDebuggerConsoleCommand(*new QScriptDebuggerScriptedConsoleCommandPrivate)
106{
107 Q_D(QScriptDebuggerScriptedConsoleCommand);
108 d->name = name;
109 d->group = group;
110 d->shortDescription = shortDescription;
111 d->longDescription = longDescription;
112 d->aliases = aliases;
113 d->seeAlso = seeAlso;
114 d->argumentTypes = argumentTypes;
115 d->subCommands = subCommands;
116 d->globalObject = globalObject;
117 d->execFunction = execFunction;
118 d->responseFunction = responseFunction;
119}
120
121QScriptDebuggerScriptedConsoleCommand::~QScriptDebuggerScriptedConsoleCommand()
122{
123}
124
125class QScriptDebuggerScriptedConsoleCommandJobPrivate;
126class QScriptDebuggerScriptedConsoleCommandJob
127 : public QScriptDebuggerConsoleCommandJob,
128 public QScriptDebuggerCommandSchedulerInterface
129{
130public:
131 QScriptDebuggerScriptedConsoleCommandJob(
132 QScriptDebuggerScriptedConsoleCommandPrivate *command,
133 const QStringList &arguments,
134 QScriptDebuggerConsole *console,
135 QScriptMessageHandlerInterface *messageHandler,
136 QScriptDebuggerCommandSchedulerInterface *commandScheduler);
137 ~QScriptDebuggerScriptedConsoleCommandJob();
138
139 int scheduleCommand(
140 const QScriptDebuggerCommand &command,
141 QScriptDebuggerResponseHandlerInterface *responseHandler);
142
143 void start();
144 void handleResponse(const QScriptDebuggerResponse &response,
145 int commandId);
146
147private:
148 Q_DECLARE_PRIVATE(QScriptDebuggerScriptedConsoleCommandJob)
149 Q_DISABLE_COPY(QScriptDebuggerScriptedConsoleCommandJob)
150};
151
152class QScriptDebuggerScriptedConsoleCommandJobPrivate
153 : public QScriptDebuggerConsoleCommandJobPrivate
154{
155public:
156 QScriptDebuggerScriptedConsoleCommandJobPrivate() : command(0), commandCount(0) {}
157 ~QScriptDebuggerScriptedConsoleCommandJobPrivate() {}
158
159 QScriptDebuggerScriptedConsoleCommandPrivate *command;
160 QStringList arguments;
161 int commandCount;
162};
163
164QScriptDebuggerScriptedConsoleCommandJob::QScriptDebuggerScriptedConsoleCommandJob(
165 QScriptDebuggerScriptedConsoleCommandPrivate *command,
166 const QStringList &arguments,
167 QScriptDebuggerConsole *console,
168 QScriptMessageHandlerInterface *messageHandler,
169 QScriptDebuggerCommandSchedulerInterface *commandScheduler)
170 : QScriptDebuggerConsoleCommandJob(*new QScriptDebuggerScriptedConsoleCommandJobPrivate,
171 console, messageHandler, commandScheduler)
172{
173 Q_D(QScriptDebuggerScriptedConsoleCommandJob);
174 d->command = command;
175 d->arguments = arguments;
176}
177
178QScriptDebuggerScriptedConsoleCommandJob::~QScriptDebuggerScriptedConsoleCommandJob()
179{
180}
181
182int QScriptDebuggerScriptedConsoleCommandJob::scheduleCommand(
183 const QScriptDebuggerCommand &command,
184 QScriptDebuggerResponseHandlerInterface *responseHandler)
185{
186 Q_D(QScriptDebuggerScriptedConsoleCommandJob);
187 ++d->commandCount;
188 return commandScheduler()->scheduleCommand(command, responseHandler);
189}
190
191void QScriptDebuggerScriptedConsoleCommandJob::start()
192{
193 Q_D(QScriptDebuggerScriptedConsoleCommandJob);
194 QScriptEngine *engine = d->command->globalObject.engine();
195 engine->setGlobalObject(d->command->globalObject);
196 QScriptValueList args;
197 for (int i = 0; i < d->arguments.size(); ++i)
198 args.append(t: QScriptValue(engine, d->arguments.at(i)));
199 QScriptDebuggerConsoleGlobalObject *global;
200 global = qobject_cast<QScriptDebuggerConsoleGlobalObject*>(object: engine->globalObject().toQObject());
201 Q_ASSERT(global != 0);
202 global->setScheduler(this);
203 global->setResponseHandler(this);
204 global->setMessageHandler(d->messageHandler);
205 global->setConsole(d->console);
206 d->commandCount = 0;
207 QScriptValue ret = d->command->execFunction.call(thisObject: QScriptValue(), args);
208 global->setScheduler(0);
209 global->setResponseHandler(0);
210 global->setMessageHandler(0);
211 global->setConsole(0);
212 if (ret.isError()) {
213 qWarning(msg: "*** internal error: %s", qPrintable(ret.toString()));
214 }
215 if (d->commandCount == 0)
216 finish();
217}
218
219void QScriptDebuggerScriptedConsoleCommandJob::handleResponse(
220 const QScriptDebuggerResponse &response,
221 int commandId)
222{
223 Q_D(QScriptDebuggerScriptedConsoleCommandJob);
224 // ### generalize
225 QScriptEngine *engine = d->command->globalObject.engine();
226 engine->setGlobalObject(d->command->globalObject);
227 QScriptValueList args;
228 args.append(t: engine->toScriptValue(value: response));
229 args.append(t: QScriptValue(engine, commandId));
230 QScriptDebuggerConsoleGlobalObject *global;
231 global = qobject_cast<QScriptDebuggerConsoleGlobalObject*>(object: d->command->globalObject.toQObject());
232 Q_ASSERT(global != 0);
233 global->setScheduler(this);
234 global->setResponseHandler(this);
235 global->setMessageHandler(d->messageHandler);
236 global->setConsole(d->console);
237 d->commandCount = 0;
238 QScriptValue ret = d->command->responseFunction.call(thisObject: QScriptValue(), args);
239 global->setScheduler(0);
240 global->setResponseHandler(0);
241 global->setMessageHandler(0);
242 global->setConsole(0);
243 if (ret.isError()) {
244 qWarning(msg: "*** internal error: %s", qPrintable(ret.toString()));
245 }
246 if (d->commandCount == 0)
247 finish();
248}
249
250/*!
251 \internal
252*/
253QString QScriptDebuggerScriptedConsoleCommand::name() const
254{
255 Q_D(const QScriptDebuggerScriptedConsoleCommand);
256 return d->name;
257}
258
259/*!
260 \internal
261*/
262QString QScriptDebuggerScriptedConsoleCommand::group() const
263{
264 Q_D(const QScriptDebuggerScriptedConsoleCommand);
265 return d->group;
266}
267
268/*!
269 \internal
270*/
271QString QScriptDebuggerScriptedConsoleCommand::shortDescription() const
272{
273 Q_D(const QScriptDebuggerScriptedConsoleCommand);
274 return d->shortDescription;
275}
276
277/*!
278 \internal
279*/
280QString QScriptDebuggerScriptedConsoleCommand::longDescription() const
281{
282 Q_D(const QScriptDebuggerScriptedConsoleCommand);
283 return d->longDescription;
284}
285
286/*!
287 \internal
288*/
289QStringList QScriptDebuggerScriptedConsoleCommand::aliases() const
290{
291 Q_D(const QScriptDebuggerScriptedConsoleCommand);
292 return d->aliases;
293}
294
295/*!
296 \internal
297*/
298QStringList QScriptDebuggerScriptedConsoleCommand::seeAlso() const
299{
300 Q_D(const QScriptDebuggerScriptedConsoleCommand);
301 return d->seeAlso;
302}
303
304/*!
305 \internal
306*/
307QStringList QScriptDebuggerScriptedConsoleCommand::argumentTypes() const
308{
309 Q_D(const QScriptDebuggerScriptedConsoleCommand);
310 return d->argumentTypes;
311}
312
313/*!
314 \internal
315*/
316QStringList QScriptDebuggerScriptedConsoleCommand::subCommands() const
317{
318 Q_D(const QScriptDebuggerScriptedConsoleCommand);
319 return d->subCommands;
320}
321
322/*!
323 \internal
324*/
325QScriptDebuggerConsoleCommandJob *QScriptDebuggerScriptedConsoleCommand::createJob(
326 const QStringList &arguments,
327 QScriptDebuggerConsole *console,
328 QScriptMessageHandlerInterface *messageHandler,
329 QScriptDebuggerCommandSchedulerInterface *commandScheduler)
330{
331 Q_D(QScriptDebuggerScriptedConsoleCommand);
332 return new QScriptDebuggerScriptedConsoleCommandJob(
333 d, arguments, console, messageHandler, commandScheduler);
334}
335
336/*!
337 Parses a command defined by the given \a program.
338 Returns an object that encapsulates the command, or 0 if parsing failed.
339*/
340QScriptDebuggerScriptedConsoleCommand *QScriptDebuggerScriptedConsoleCommand::parse(
341 const QString &program, const QString &fileName,
342 QScriptEngine *engine, QScriptMessageHandlerInterface *messageHandler)
343{
344 // create a custom global object
345 QScriptDebuggerConsoleGlobalObject *cppGlobal = new QScriptDebuggerConsoleGlobalObject();
346 QScriptValue global = engine->newQObject(object: cppGlobal,
347 ownership: QScriptEngine::ScriptOwnership,
348 options: QScriptEngine::ExcludeSuperClassContents);
349 {
350 QScriptValueIterator it(engine->globalObject());
351 while (it.hasNext()) {
352 it.next();
353 global.setProperty(name: it.scriptName(), value: it.value(), flags: it.flags());
354 }
355 }
356 engine->setGlobalObject(global);
357
358 cppGlobal->setMessageHandler(messageHandler);
359 QScriptValue ret = engine->evaluate(program, fileName);
360 cppGlobal->setMessageHandler(0);
361 if (engine->hasUncaughtException()) {
362 messageHandler->message(type: QtCriticalMsg, text: ret.toString(), fileName,
363 lineNumber: engine->uncaughtExceptionLineNumber());
364 return 0;
365 }
366
367 QScriptValue name = global.property(name: QLatin1String("name"));
368 if (!name.isString()) {
369 messageHandler->message(type: QtCriticalMsg, text: QLatin1String("command definition lacks a name"), fileName);
370 return 0;
371 }
372 QString nameStr = name.toString();
373
374 QScriptValue group = global.property(name: QLatin1String("group"));
375 if (!group.isString()) {
376 messageHandler->message(type: QtCriticalMsg, text: QString::fromLatin1(str: "definition of command \"%0\" lacks a group name")
377 .arg(a: nameStr), fileName);
378 return 0;
379 }
380 QString groupStr = group.toString();
381
382 QScriptValue shortDesc = global.property(name: QLatin1String("shortDescription"));
383 if (!shortDesc.isString()) {
384 messageHandler->message(type: QtCriticalMsg, text: QString::fromLatin1(str: "definition of command \"%0\" lacks shortDescription")
385 .arg(a: nameStr), fileName);
386 return 0;
387 }
388 QString shortDescStr = shortDesc.toString();
389
390 QScriptValue longDesc = global.property(name: QLatin1String("longDescription"));
391 if (!longDesc.isString()) {
392 messageHandler->message(type: QtCriticalMsg, text: QString::fromLatin1(str: "definition of command \"%0\" lacks longDescription")
393 .arg(a: nameStr), fileName);
394 return 0;
395 }
396 QString longDescStr = longDesc.toString();
397
398 QStringList aliases;
399 qScriptValueToSequence(value: global.property(name: QLatin1String("aliases")), cont&: aliases);
400
401 QStringList seeAlso;
402 qScriptValueToSequence(value: global.property(name: QLatin1String("seeAlso")), cont&: seeAlso);
403
404 QStringList argTypes;
405 qScriptValueToSequence(value: global.property(name: QLatin1String("argumentTypes")), cont&: argTypes);
406
407 QStringList subCommands;
408 qScriptValueToSequence(value: global.property(name: QLatin1String("subCommands")), cont&: subCommands);
409
410 QScriptValue execFunction = global.property(name: QLatin1String("execute"));
411 if (!execFunction.isFunction()) {
412 messageHandler->message(type: QtCriticalMsg, text: QString::fromLatin1(str: "definition of command \"%0\" lacks execute() function")
413 .arg(a: nameStr), fileName);
414 return 0;
415 }
416
417 QScriptValue responseFunction = global.property(name: QLatin1String("handleResponse"));
418
419 QScriptDebuggerScriptedConsoleCommand *result = new QScriptDebuggerScriptedConsoleCommand(
420 nameStr, groupStr,
421 shortDescStr, longDescStr,
422 aliases, seeAlso,
423 argTypes, subCommands,
424 global, execFunction, responseFunction);
425 return result;
426}
427
428QT_END_NAMESPACE
429

source code of qtscript/src/scripttools/debugging/qscriptdebuggerscriptedconsolecommand.cpp