1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtScxml 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#ifndef QSCXMLEXECUTABLECONTENT_P_H
41#define QSCXMLEXECUTABLECONTENT_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtScxml/qscxmlexecutablecontent.h>
55#include <QtScxml/private/qscxmltabledata_p.h>
56#include <QtScxml/private/qscxmlcompiler_p.h>
57#include <QtCore/qtextstream.h>
58
59#ifndef BUILD_QSCXMLC
60#include <QtScxml/qscxmldatamodel.h>
61#include <QtScxml/qscxmlstatemachine.h>
62#endif // BUILD_QSCXMLC
63
64QT_BEGIN_NAMESPACE
65
66namespace QScxmlExecutableContent {
67
68static inline bool operator<(const EvaluatorInfo &ei1, const EvaluatorInfo &ei2)
69{
70 if (ei1.expr != ei2.expr)
71 return ei1.expr < ei2.expr;
72 else
73 return ei1.context < ei2.context;
74}
75
76static inline bool operator<(const AssignmentInfo &ai1, const AssignmentInfo &ai2)
77{
78 if (ai1.dest != ai2.dest)
79 return ai1.dest < ai2.dest;
80 else if (ai1.expr != ai2.expr)
81 return ai1.expr < ai2.expr;
82 else
83 return ai1.context < ai2.context;
84}
85
86static inline bool operator<(const ForeachInfo &fi1, const ForeachInfo &fi2)
87{
88 if (fi1.array != fi2.array) return fi1.array < fi2.array;
89 if (fi1.item != fi2.item) return fi1.item < fi2.item;
90 if (fi1.index != fi2.index) return fi1.index < fi2.index;
91 return fi1.context < fi2.context;
92}
93
94#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
95#pragma pack(push, 4) // 4 == sizeof(qint32)
96#endif
97
98template <typename T>
99struct Array
100{
101 qint32 count;
102 // T[] data;
103 T *data() { return const_cast<T *>(const_data()); }
104 const T *const_data() const { return reinterpret_cast<const T *>(reinterpret_cast<const char *>(this) + sizeof(Array<T>)); }
105
106 const T &at(int pos) const { return *(const_data() + pos); }
107 int dataSize() const { return count * sizeof(T) / sizeof(qint32); }
108 int size() const { return sizeof(Array<T>) / sizeof(qint32) + dataSize(); }
109};
110
111struct Q_SCXML_EXPORT Instruction
112{
113 enum InstructionType: qint32 {
114 Sequence = 1,
115 Sequences,
116 Send,
117 Raise,
118 Log,
119 JavaScript,
120 Assign,
121 Initialize,
122 If,
123 Foreach,
124 Cancel,
125 DoneData
126 } instructionType;
127};
128
129struct Q_SCXML_EXPORT DoneData: Instruction
130{
131 StringId location;
132 StringId contents;
133 EvaluatorId expr;
134 Array<ParameterInfo> params;
135
136 static InstructionType kind() { return Instruction::DoneData; }
137};
138
139struct Q_SCXML_EXPORT InstructionSequence: Instruction
140{
141 qint32 entryCount; // the amount of qint32's that the instructions take up
142 // Instruction[] instructions;
143
144 static InstructionType kind() { return Instruction::Sequence; }
145 const InstructionId *instructions() const
146 {
147 return reinterpret_cast<const InstructionId *>(this)
148 + sizeof(InstructionSequence) / sizeof(qint32);
149 }
150 int size() const { return sizeof(InstructionSequence) / sizeof(qint32) + entryCount; }
151};
152
153struct Q_SCXML_EXPORT InstructionSequences: Instruction
154{
155 qint32 sequenceCount;
156 qint32 entryCount; // the amount of qint32's that the sequences take up
157 // InstructionSequence[] sequences;
158
159 static InstructionType kind() { return Instruction::Sequences; }
160 const InstructionSequence *sequences() const {
161 return reinterpret_cast<const InstructionSequence *>(
162 reinterpret_cast<const InstructionId *>(this)
163 + sizeof(InstructionSequences) / sizeof(qint32));
164 }
165 int size() const { return sizeof(InstructionSequences)/sizeof(qint32) + entryCount; }
166 const InstructionId *at(int pos) const
167 {
168 const InstructionId *seq = reinterpret_cast<const InstructionId *>(sequences());
169 while (pos--) {
170 seq += reinterpret_cast<const InstructionSequence *>(seq)->size();
171 }
172 return seq;
173 }
174};
175
176struct Q_SCXML_EXPORT Send: Instruction
177{
178 StringId instructionLocation;
179 StringId event;
180 EvaluatorId eventexpr;
181 StringId type;
182 EvaluatorId typeexpr;
183 StringId target;
184 EvaluatorId targetexpr;
185 StringId id;
186 StringId idLocation;
187 StringId delay;
188 EvaluatorId delayexpr;
189 StringId content;
190 EvaluatorId contentexpr;
191 Array<StringId> namelist;
192// Array<Param> params;
193
194 static InstructionType kind() { return Instruction::Send; }
195
196 int paramsOffset() const
197 {
198 return sizeof(Send) / sizeof(qint32) + namelist.dataSize();
199 }
200
201 int size() const
202 {
203 return paramsOffset() + params()->size();
204 }
205
206 const Array<ParameterInfo> *params() const {
207 return reinterpret_cast<const Array<ParameterInfo> *>(
208 reinterpret_cast<const InstructionId *>(this) + paramsOffset());
209 }
210
211 Array<ParameterInfo> *params() {
212 return reinterpret_cast<Array<ParameterInfo> *>(
213 reinterpret_cast<InstructionId *>(this) + paramsOffset());
214 }
215
216 static int calculateExtraSize(int paramCount, int nameCount) {
217 return 1 + paramCount * sizeof(ParameterInfo) / sizeof(qint32)
218 + nameCount * sizeof(StringId) / sizeof(qint32);
219 }
220};
221
222struct Q_SCXML_EXPORT Raise: Instruction
223{
224 StringId event;
225
226 static InstructionType kind() { return Instruction::Raise; }
227 int size() const { return sizeof(Raise) / sizeof(qint32); }
228};
229
230struct Q_SCXML_EXPORT Log: Instruction
231{
232 StringId label;
233 EvaluatorId expr;
234
235 static InstructionType kind() { return Instruction::Log; }
236 int size() const { return sizeof(Log) / sizeof(qint32); }
237};
238
239struct Q_SCXML_EXPORT JavaScript: Instruction
240{
241 EvaluatorId go;
242
243 static InstructionType kind() { return Instruction::JavaScript; }
244 int size() const { return sizeof(JavaScript) / sizeof(qint32); }
245};
246
247struct Q_SCXML_EXPORT Assign: Instruction
248{
249 EvaluatorId expression;
250
251 static InstructionType kind() { return Instruction::Assign; }
252 int size() const { return sizeof(Assign) / sizeof(qint32); }
253};
254
255struct Q_SCXML_EXPORT Initialize: Instruction
256{
257 EvaluatorId expression;
258
259 static InstructionType kind() { return Instruction::Initialize; }
260 int size() const { return sizeof(Initialize) / sizeof(qint32); }
261};
262
263struct Q_SCXML_EXPORT If: Instruction
264{
265 Array<EvaluatorId> conditions;
266 // InstructionSequences blocks;
267 const InstructionSequences *blocks() const {
268 return reinterpret_cast<const InstructionSequences *>(
269 reinterpret_cast<const InstructionId *>(this) + sizeof(If) / sizeof(qint32)
270 + conditions.dataSize());
271 }
272
273 static InstructionType kind() { return Instruction::If; }
274 int size() const
275 {
276 return sizeof(If) / sizeof(qint32) + blocks()->size() + conditions.dataSize();
277 }
278};
279
280struct Q_SCXML_EXPORT Foreach: Instruction
281{
282 EvaluatorId doIt;
283 InstructionSequence block;
284
285 static InstructionType kind() { return Instruction::Foreach; }
286 int size() const { return sizeof(Foreach) / sizeof(qint32) + block.entryCount; }
287 const InstructionId *blockstart() const
288 {
289 return reinterpret_cast<const InstructionId *>(&block);
290 }
291};
292
293struct Q_SCXML_EXPORT Cancel: Instruction
294{
295 StringId sendid;
296 EvaluatorId sendidexpr;
297
298 static InstructionType kind() { return Instruction::Cancel; }
299 int size() const { return sizeof(Cancel) / sizeof(qint32); }
300};
301
302struct StateTable {
303 int version;
304 int name;
305 enum: int {
306 InvalidDataModel = -1,
307 NullDataModel = 0,
308 EcmaScriptDataModel = 1,
309 CppDataModel = 2
310 } dataModel;
311 int childStates; // offset into offsets
312 int initialTransition;
313 int initialSetup;
314 enum: int { InvalidBinding = -1, EarlyBinding = 0, LateBinding = 1 } binding;
315 int maxServiceId;
316 int stateOffset, stateCount;
317 int transitionOffset, transitionCount;
318 int arrayOffset, arraySize;
319
320 enum { terminator = 0xc0ff33 };
321 enum { InvalidIndex = -1 };
322
323 struct State {
324 int name;
325 int parent;
326 enum: int {
327 Invalid = -1,
328 Normal = 0,
329 Parallel = 1,
330 Final = 2,
331 ShallowHistory = 3,
332 DeepHistory = 4
333 } type;
334 int initialTransition;
335 int initInstructions;
336 int entryInstructions;
337 int exitInstructions;
338 int doneData;
339 int childStates; // offset into arrays
340 int transitions; // offset into arrays
341 int serviceFactoryIds; // offset into arrays
342
343 State()
344 : name(InvalidIndex)
345 , parent(InvalidIndex)
346 , type(Invalid)
347 , initialTransition(InvalidIndex)
348 , initInstructions(InvalidIndex)
349 , entryInstructions(InvalidIndex)
350 , exitInstructions(InvalidIndex)
351 , doneData(InvalidIndex)
352 , childStates(InvalidIndex)
353 , transitions(InvalidIndex)
354 , serviceFactoryIds(InvalidIndex)
355 {}
356
357 bool isAtomic() const
358 { return childStates == InvalidIndex; }
359
360 bool isCompound() const
361 { return type == Normal && childStates != InvalidIndex; }
362
363 bool parentIsScxmlElement() const
364 { return parent == InvalidIndex; }
365
366 bool isHistoryState() const
367 { return type == ShallowHistory || type == DeepHistory; }
368
369 bool isParallel() const
370 { return type == Parallel; }
371 };
372
373 struct Transition {
374 int events; // offset into offsets
375 int condition;
376 enum: int {
377 Invalid = -1,
378 Internal = 0,
379 External = 1,
380 Synthetic = 2
381 } type;
382 int source;
383 int targets; // offset into offsets
384 int transitionInstructions;
385
386 Transition()
387 : events(InvalidIndex)
388 , condition(InvalidIndex)
389 , type(Invalid)
390 , source(InvalidIndex)
391 , targets(InvalidIndex)
392 , transitionInstructions(InvalidIndex)
393 {}
394 };
395
396 struct Array {
397 Array(const int *start): start(start) {}
398 int size() const { return *start; }
399 bool isValid() const { return start != nullptr; }
400
401 int operator[](int idx) const {
402 Q_ASSERT(idx >= 0);
403 Q_ASSERT(idx < size());
404 return *(start + idx + 1);
405 }
406
407 struct const_iterator: public std::iterator<std::forward_iterator_tag, int, ptrdiff_t,
408 const int *, const int &>
409 {
410 const_iterator(const Array &a, int pos): a(a), pos(pos) {}
411
412 const_iterator &operator++() {
413 if (pos < a.size()) ++pos;
414 return *this;
415 }
416
417 bool operator==(const const_iterator &other) const
418 { return &other.a == &a && other.pos == pos; }
419
420 bool operator!=(const StateTable::Array::const_iterator &other)
421 { return !this->operator==(other); }
422
423 int operator*() const {
424 if (pos < a.size())
425 return a[pos];
426 else
427 return -1;
428 }
429
430 private:
431 const Array &a;
432 int pos;
433 };
434
435 const_iterator begin() const
436 { return const_iterator(*this, 0); }
437
438 const_iterator end() const
439 { return const_iterator(*this, size()); }
440
441 private:
442 const int *start;
443 };
444
445 StateTable()
446 : version(InvalidIndex)
447 , name(InvalidIndex)
448 , dataModel(InvalidDataModel)
449 , childStates(InvalidIndex)
450 , initialTransition(InvalidIndex)
451 , initialSetup(InvalidIndex)
452 , binding(InvalidBinding)
453 , maxServiceId(InvalidIndex)
454 , stateOffset(InvalidIndex), stateCount(InvalidIndex)
455 , transitionOffset(InvalidIndex), transitionCount(InvalidIndex)
456 , arrayOffset(InvalidIndex), arraySize(InvalidIndex)
457 {}
458
459 const State &state(int idx) const
460 {
461 Q_ASSERT(idx >= 0);
462 Q_ASSERT(idx < stateCount);
463 return reinterpret_cast<const State *>(
464 reinterpret_cast<const int *>(this) + stateOffset)[idx];
465 }
466
467 const Transition &transition(int idx) const
468 {
469 Q_ASSERT(idx >= 0);
470 Q_ASSERT(idx < transitionCount);
471 return reinterpret_cast<const Transition *>(
472 reinterpret_cast<const int *>(this) + transitionOffset)[idx];
473 }
474
475 const Array array(int idx) const
476 {
477 Q_ASSERT(idx < arraySize);
478 if (idx >= 0) {
479 const int *start = reinterpret_cast<const int *>(this) + arrayOffset + idx;
480 Q_ASSERT(*start + idx < arraySize);
481 return Array(start);
482 } else {
483 return Array(nullptr);
484 }
485 }
486};
487
488#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
489#pragma pack(pop)
490#endif
491
492} // QScxmlExecutableContent namespace
493
494class QScxmlExecutionEngine
495{
496 Q_DISABLE_COPY(QScxmlExecutionEngine)
497
498public:
499 QScxmlExecutionEngine(QScxmlStateMachine *stateMachine);
500
501 bool execute(QScxmlExecutableContent::ContainerId ip, const QVariant &extraData = QVariant());
502
503private:
504 const QScxmlExecutableContent::InstructionId *step(
505 const QScxmlExecutableContent::InstructionId *ip, bool *ok);
506
507 QScxmlStateMachine *stateMachine;
508 QVariant extraData;
509};
510
511QT_END_NAMESPACE
512
513#endif // QSCXMLEXECUTABLECONTENT_P_H
514

source code of qtscxml/src/scxml/qscxmlexecutablecontent_p.h