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 QSCXMLCOMPILER_P_H 41 #define QSCXMLCOMPILER_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 "qscxmlcompiler.h" 55 56 #include <QtCore/qdir.h> 57 #include <QtCore/qfileinfo.h> 58 #include <QtCore/qset.h> 59 #include <QtCore/qsharedpointer.h> 60 #include <QtCore/qstringlist.h> 61 #include <QtCore/qstring.h> 62 #include <QtCore/qxmlstream.h> 63 64 QT_BEGIN_NAMESPACE 65 66 namespace DocumentModel { 67 68 struct XmlLocation 69 { 70 int line; 71 int column; 72 XmlLocationXmlLocation73 XmlLocation(int theLine, int theColumn): line(theLine), column(theColumn) {} 74 }; 75 76 struct If; 77 struct Send; 78 struct Invoke; 79 struct Script; 80 struct AbstractState; 81 struct State; 82 struct Transition; 83 struct HistoryState; 84 struct Scxml; 85 class NodeVisitor; 86 struct Node { 87 XmlLocation xmlLocation; 88 NodeNode89 Node(const XmlLocation &theLocation): xmlLocation(theLocation) {} 90 virtual ~Node(); 91 virtual void accept(NodeVisitor *visitor) = 0; 92 asIfNode93 virtual If *asIf() { return nullptr; } asSendNode94 virtual Send *asSend() { return nullptr; } asInvokeNode95 virtual Invoke *asInvoke() { return nullptr; } asScriptNode96 virtual Script *asScript() { return nullptr; } asStateNode97 virtual State *asState() { return nullptr; } asTransitionNode98 virtual Transition *asTransition() { return nullptr; } asHistoryStateNode99 virtual HistoryState *asHistoryState() { return nullptr; } asScxmlNode100 virtual Scxml *asScxml() { return nullptr; } 101 AbstractState *asAbstractState(); 102 103 private: 104 Q_DISABLE_COPY(Node) 105 }; 106 107 struct DataElement: public Node 108 { 109 QString id; 110 QString src; 111 QString expr; 112 QString content; 113 DataElementDataElement114 DataElement(const XmlLocation &xmlLocation): Node(xmlLocation) {} 115 void accept(NodeVisitor *visitor) override; 116 }; 117 118 struct Param: public Node 119 { 120 QString name; 121 QString expr; 122 QString location; 123 ParamParam124 Param(const XmlLocation &xmlLocation): Node(xmlLocation) {} 125 void accept(NodeVisitor *visitor) override; 126 }; 127 128 struct DoneData: public Node 129 { 130 QString contents; 131 QString expr; 132 QVector<Param *> params; 133 DoneDataDoneData134 DoneData(const XmlLocation &xmlLocation): Node(xmlLocation) {} 135 void accept(NodeVisitor *visitor) override; 136 }; 137 138 struct Instruction: public Node 139 { InstructionInstruction140 Instruction(const XmlLocation &xmlLocation): Node(xmlLocation) {} ~InstructionInstruction141 virtual ~Instruction() {} 142 }; 143 144 typedef QVector<Instruction *> InstructionSequence; 145 typedef QVector<InstructionSequence *> InstructionSequences; 146 147 struct Send: public Instruction 148 { 149 QString event; 150 QString eventexpr; 151 QString type; 152 QString typeexpr; 153 QString target; 154 QString targetexpr; 155 QString id; 156 QString idLocation; 157 QString delay; 158 QString delayexpr; 159 QStringList namelist; 160 QVector<Param *> params; 161 QString content; 162 QString contentexpr; 163 SendSend164 Send(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} asSendSend165 Send *asSend() override { return this; } 166 void accept(NodeVisitor *visitor) override; 167 }; 168 169 struct ScxmlDocument; 170 struct Invoke: public Instruction 171 { 172 QString type; 173 QString typeexpr; 174 QString src; 175 QString srcexpr; 176 QString id; 177 QString idLocation; 178 QStringList namelist; 179 bool autoforward; 180 QVector<Param *> params; 181 InstructionSequence finalize; 182 183 QSharedPointer<ScxmlDocument> content; 184 InvokeInvoke185 Invoke(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} asInvokeInvoke186 Invoke *asInvoke() override { return this; } 187 void accept(NodeVisitor *visitor) override; 188 }; 189 190 struct Raise: public Instruction 191 { 192 QString event; 193 RaiseRaise194 Raise(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} 195 void accept(NodeVisitor *visitor) override; 196 }; 197 198 struct Log: public Instruction 199 { 200 QString label, expr; 201 LogLog202 Log(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} 203 void accept(NodeVisitor *visitor) override; 204 }; 205 206 struct Script: public Instruction 207 { 208 QString src; 209 QString content; 210 ScriptScript211 Script(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} asScriptScript212 Script *asScript() override { return this; } 213 void accept(NodeVisitor *visitor) override; 214 }; 215 216 struct Assign: public Instruction 217 { 218 QString location; 219 QString expr; 220 QString content; 221 AssignAssign222 Assign(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} 223 void accept(NodeVisitor *visitor) override; 224 }; 225 226 struct If: public Instruction 227 { 228 QStringList conditions; 229 InstructionSequences blocks; 230 IfIf231 If(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} asIfIf232 If *asIf() override { return this; } 233 void accept(NodeVisitor *visitor) override; 234 }; 235 236 struct Foreach: public Instruction 237 { 238 QString array; 239 QString item; 240 QString index; 241 InstructionSequence block; 242 ForeachForeach243 Foreach(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} 244 void accept(NodeVisitor *visitor) override; 245 }; 246 247 struct Cancel: public Instruction 248 { 249 QString sendid; 250 QString sendidexpr; 251 CancelCancel252 Cancel(const XmlLocation &xmlLocation): Instruction(xmlLocation) {} 253 void accept(NodeVisitor *visitor) override; 254 }; 255 256 struct StateOrTransition: public Node 257 { StateOrTransitionStateOrTransition258 StateOrTransition(const XmlLocation &xmlLocation): Node(xmlLocation) {} 259 }; 260 261 struct StateContainer 262 { StateContainerStateContainer263 StateContainer() 264 : parent(nullptr) 265 {} 266 267 StateContainer *parent; 268 ~StateContainerStateContainer269 virtual ~StateContainer() {} 270 virtual void add(StateOrTransition *s) = 0; asAbstractStateStateContainer271 virtual AbstractState *asAbstractState() { return nullptr; } asStateStateContainer272 virtual State *asState() { return nullptr; } asScxmlStateContainer273 virtual Scxml *asScxml() { return nullptr; } 274 }; 275 276 struct AbstractState: public StateContainer 277 { 278 QString id; 279 asAbstractStateAbstractState280 AbstractState *asAbstractState() override { return this; } 281 }; 282 283 struct State: public AbstractState, public StateOrTransition 284 { 285 enum Type { Normal, Parallel, Final }; 286 287 QStringList initial; 288 QVector<DataElement *> dataElements; 289 QVector<StateOrTransition *> children; 290 InstructionSequences onEntry; 291 InstructionSequences onExit; 292 DoneData *doneData; 293 QVector<Invoke *> invokes; 294 Type type; 295 296 Transition *initialTransition; // when not set, it is filled during verification 297 StateState298 State(const XmlLocation &xmlLocation) 299 : StateOrTransition(xmlLocation) 300 , doneData(nullptr) 301 , type(Normal) 302 , initialTransition(nullptr) 303 {} 304 addState305 void add(StateOrTransition *s) override 306 { 307 Q_ASSERT(s); 308 children.append(s); 309 } 310 asStateState311 State *asState() override { return this; } 312 313 void accept(NodeVisitor *visitor) override; 314 }; 315 316 struct Transition: public StateOrTransition 317 { 318 enum Type { Internal, External, Synthetic }; 319 QStringList events; 320 QScopedPointer<QString> condition; 321 QStringList targets; 322 InstructionSequence instructionsOnTransition; 323 Type type; 324 325 QVector<AbstractState *> targetStates; // when not set, it is filled during verification 326 TransitionTransition327 Transition(const XmlLocation &xmlLocation) 328 : StateOrTransition(xmlLocation) 329 , type(External) 330 {} 331 asTransitionTransition332 Transition *asTransition() override { return this; } 333 334 void accept(NodeVisitor *visitor) override; 335 }; 336 337 struct HistoryState: public AbstractState, public StateOrTransition 338 { 339 enum Type { Deep, Shallow }; 340 Type type; 341 QVector<StateOrTransition *> children; 342 HistoryStateHistoryState343 HistoryState(const XmlLocation &xmlLocation) 344 : StateOrTransition(xmlLocation) 345 , type(Shallow) 346 {} 347 addHistoryState348 void add(StateOrTransition *s) override 349 { 350 Q_ASSERT(s); 351 children.append(s); 352 } 353 defaultConfigurationHistoryState354 Transition *defaultConfiguration() 355 { return children.isEmpty() ? nullptr : children.first()->asTransition(); } 356 asHistoryStateHistoryState357 HistoryState *asHistoryState() override { return this; } 358 void accept(NodeVisitor *visitor) override; 359 }; 360 361 struct Scxml: public StateContainer, public Node 362 { 363 enum DataModelType { 364 NullDataModel, 365 JSDataModel, 366 CppDataModel 367 }; 368 enum BindingMethod { 369 EarlyBinding, 370 LateBinding 371 }; 372 373 QStringList initial; 374 QString name; 375 DataModelType dataModel; 376 QString cppDataModelClassName; 377 QString cppDataModelHeaderName; 378 BindingMethod binding; 379 QVector<StateOrTransition *> children; 380 QVector<DataElement *> dataElements; 381 QScopedPointer<Script> script; 382 InstructionSequence initialSetup; 383 384 Transition *initialTransition; 385 ScxmlScxml386 Scxml(const XmlLocation &xmlLocation) 387 : Node(xmlLocation) 388 , dataModel(NullDataModel) 389 , binding(EarlyBinding) 390 , initialTransition(nullptr) 391 {} 392 addScxml393 void add(StateOrTransition *s) override 394 { 395 Q_ASSERT(s); 396 children.append(s); 397 } 398 asScxmlScxml399 Scxml *asScxml() override { return this; } 400 401 void accept(NodeVisitor *visitor) override; 402 }; 403 404 struct ScxmlDocument 405 { 406 const QString fileName; 407 Scxml *root; 408 QVector<AbstractState *> allStates; 409 QVector<Transition *> allTransitions; 410 QVector<Node *> allNodes; 411 QVector<InstructionSequence *> allSequences; 412 QVector<ScxmlDocument *> allSubDocuments; // weak pointers 413 bool isVerified; 414 ScxmlDocumentScxmlDocument415 ScxmlDocument(const QString &fileName) 416 : fileName(fileName) 417 , root(nullptr) 418 , isVerified(false) 419 {} 420 ~ScxmlDocumentScxmlDocument421 ~ScxmlDocument() 422 { 423 delete root; 424 qDeleteAll(allNodes); 425 qDeleteAll(allSequences); 426 } 427 newStateScxmlDocument428 State *newState(StateContainer *parent, State::Type type, const XmlLocation &xmlLocation) 429 { 430 Q_ASSERT(parent); 431 State *s = newNode<State>(xmlLocation); 432 s->parent = parent; 433 s->type = type; 434 allStates.append(s); 435 parent->add(s); 436 return s; 437 } 438 newHistoryStateScxmlDocument439 HistoryState *newHistoryState(StateContainer *parent, const XmlLocation &xmlLocation) 440 { 441 Q_ASSERT(parent); 442 HistoryState *s = newNode<HistoryState>(xmlLocation); 443 s->parent = parent; 444 allStates.append(s); 445 parent->add(s); 446 return s; 447 } 448 newTransitionScxmlDocument449 Transition *newTransition(StateContainer *parent, const XmlLocation &xmlLocation) 450 { 451 Transition *t = newNode<Transition>(xmlLocation); 452 allTransitions.append(t); 453 if (parent != nullptr) { 454 parent->add(t); 455 } 456 return t; 457 } 458 459 template<typename T> newNodeScxmlDocument460 T *newNode(const XmlLocation &xmlLocation) 461 { 462 T *node = new T(xmlLocation); 463 allNodes.append(node); 464 return node; 465 } 466 newSequenceScxmlDocument467 InstructionSequence *newSequence(InstructionSequences *container) 468 { 469 Q_ASSERT(container); 470 InstructionSequence *is = new InstructionSequence; 471 allSequences.append(is); 472 container->append(is); 473 return is; 474 } 475 }; 476 477 class Q_SCXML_EXPORT NodeVisitor 478 { 479 public: 480 virtual ~NodeVisitor(); 481 visit(DataElement *)482 virtual void visit(DataElement *) {} visit(Param *)483 virtual void visit(Param *) {} visit(DoneData *)484 virtual bool visit(DoneData *) { return true; } endVisit(DoneData *)485 virtual void endVisit(DoneData *) {} visit(Send *)486 virtual bool visit(Send *) { return true; } endVisit(Send *)487 virtual void endVisit(Send *) {} visit(Invoke *)488 virtual bool visit(Invoke *) { return true; } endVisit(Invoke *)489 virtual void endVisit(Invoke *) {} visit(Raise *)490 virtual void visit(Raise *) {} visit(Log *)491 virtual void visit(Log *) {} visit(Script *)492 virtual void visit(Script *) {} visit(Assign *)493 virtual void visit(Assign *) {} visit(If *)494 virtual bool visit(If *) { return true; } endVisit(If *)495 virtual void endVisit(If *) {} visit(Foreach *)496 virtual bool visit(Foreach *) { return true; } endVisit(Foreach *)497 virtual void endVisit(Foreach *) {} visit(Cancel *)498 virtual void visit(Cancel *) {} visit(State *)499 virtual bool visit(State *) { return true; } endVisit(State *)500 virtual void endVisit(State *) {} visit(Transition *)501 virtual bool visit(Transition *) { return true; } endVisit(Transition *)502 virtual void endVisit(Transition *) {} visit(HistoryState *)503 virtual bool visit(HistoryState *) { return true; } endVisit(HistoryState *)504 virtual void endVisit(HistoryState *) {} visit(Scxml *)505 virtual bool visit(Scxml *) { return true; } endVisit(Scxml *)506 virtual void endVisit(Scxml *) {} 507 visit(InstructionSequence * sequence)508 void visit(InstructionSequence *sequence) 509 { 510 Q_ASSERT(sequence); 511 for (Instruction *instruction : qAsConst(*sequence)) { 512 Q_ASSERT(instruction); 513 instruction->accept(this); 514 } 515 } 516 visit(const QVector<DataElement * > & dataElements)517 void visit(const QVector<DataElement *> &dataElements) 518 { 519 for (DataElement *dataElement : dataElements) { 520 Q_ASSERT(dataElement); 521 dataElement->accept(this); 522 } 523 } 524 visit(const QVector<StateOrTransition * > & children)525 void visit(const QVector<StateOrTransition *> &children) 526 { 527 for (StateOrTransition *child : children) { 528 Q_ASSERT(child); 529 child->accept(this); 530 } 531 } 532 visit(const InstructionSequences & sequences)533 void visit(const InstructionSequences &sequences) 534 { 535 for (InstructionSequence *sequence : sequences) { 536 Q_ASSERT(sequence); 537 visit(sequence); 538 } 539 } 540 visit(const QVector<Param * > & params)541 void visit(const QVector<Param *> ¶ms) 542 { 543 for (Param *param : params) { 544 Q_ASSERT(param); 545 param->accept(this); 546 } 547 } 548 }; 549 550 } // DocumentModel namespace 551 552 class Q_SCXML_EXPORT QScxmlCompilerPrivate 553 { 554 public: 555 static QScxmlCompilerPrivate *get(QScxmlCompiler *compiler); 556 557 QScxmlCompilerPrivate(QXmlStreamReader *reader); 558 559 bool verifyDocument(); 560 DocumentModel::ScxmlDocument *scxmlDocument() const; 561 562 QString fileName() const; 563 void setFileName(const QString &fileName); 564 565 QScxmlCompiler::Loader *loader() const; 566 void setLoader(QScxmlCompiler::Loader *loader); 567 568 bool readDocument(); 569 void parseSubDocument(DocumentModel::Invoke *parentInvoke, 570 QXmlStreamReader *reader, 571 const QString &fileName); 572 bool parseSubElement(DocumentModel::Invoke *parentInvoke, 573 QXmlStreamReader *reader, 574 const QString &fileName); 575 QByteArray load(const QString &name, bool *ok); 576 577 QVector<QScxmlError> errors() const; 578 579 void addError(const QString &msg); 580 void addError(const DocumentModel::XmlLocation &location, const QString &msg); 581 QScxmlStateMachine *instantiateStateMachine() const; 582 void instantiateDataModel(QScxmlStateMachine *stateMachine) const; 583 584 private: 585 DocumentModel::AbstractState *currentParent() const; 586 DocumentModel::XmlLocation xmlLocation() const; 587 bool maybeId(const QXmlStreamAttributes &attributes, QString *id); 588 DocumentModel::If *lastIf(); 589 bool checkAttributes(const QXmlStreamAttributes &attributes, 590 const QStringList &requiredNames, 591 const QStringList &optionalNames); 592 593 bool preReadElementScxml(); 594 bool preReadElementState(); 595 bool preReadElementParallel(); 596 bool preReadElementInitial(); 597 bool preReadElementTransition(); 598 bool preReadElementFinal(); 599 bool preReadElementHistory(); 600 bool preReadElementOnEntry(); 601 bool preReadElementOnExit(); 602 bool preReadElementRaise(); 603 bool preReadElementIf(); 604 bool preReadElementElseIf(); 605 bool preReadElementElse(); 606 bool preReadElementForeach(); 607 bool preReadElementLog(); 608 bool preReadElementDataModel(); 609 bool preReadElementData(); 610 bool preReadElementAssign(); 611 bool preReadElementDoneData(); 612 bool preReadElementContent(); 613 bool preReadElementParam(); 614 bool preReadElementScript(); 615 bool preReadElementSend(); 616 bool preReadElementCancel(); 617 bool preReadElementInvoke(); 618 bool preReadElementFinalize(); 619 620 bool postReadElementScxml(); 621 bool postReadElementState(); 622 bool postReadElementParallel(); 623 bool postReadElementInitial(); 624 bool postReadElementTransition(); 625 bool postReadElementFinal(); 626 bool postReadElementHistory(); 627 bool postReadElementOnEntry(); 628 bool postReadElementOnExit(); 629 bool postReadElementRaise(); 630 bool postReadElementIf(); 631 bool postReadElementElseIf(); 632 bool postReadElementElse(); 633 bool postReadElementForeach(); 634 bool postReadElementLog(); 635 bool postReadElementDataModel(); 636 bool postReadElementData(); 637 bool postReadElementAssign(); 638 bool postReadElementDoneData(); 639 bool postReadElementContent(); 640 bool postReadElementParam(); 641 bool postReadElementScript(); 642 bool postReadElementSend(); 643 bool postReadElementCancel(); 644 bool postReadElementInvoke(); 645 bool postReadElementFinalize(); 646 647 bool readElement(); 648 649 void resetDocument(); 650 void currentStateUp(); 651 bool flushInstruction(); 652 653 private: 654 struct ParserState { 655 enum Kind { 656 Scxml, 657 State, 658 Parallel, 659 Transition, 660 Initial, 661 Final, 662 OnEntry, 663 OnExit, 664 History, 665 Raise, 666 If, 667 ElseIf, 668 Else, 669 Foreach, 670 Log, 671 DataModel, 672 Data, 673 Assign, 674 DoneData, 675 Content, 676 Param, 677 Script, 678 Send, 679 Cancel, 680 Invoke, 681 Finalize, 682 None 683 }; 684 Kind kind; 685 QString chars; 686 DocumentModel::Instruction *instruction; 687 DocumentModel::InstructionSequence *instructionContainer; 688 689 bool collectChars(); 690 691 ParserState(Kind someKind = None); ~ParserStateParserState692 ~ParserState() { } 693 694 bool validChild(ParserState::Kind child) const; 695 static bool validChild(ParserState::Kind parent, ParserState::Kind child); 696 static bool isExecutableContent(ParserState::Kind kind); 697 static Kind nameToParserStateKind(const QStringRef &name); 698 static QStringList requiredAttributes(Kind kind); 699 static QStringList optionalAttributes(Kind kind); 700 }; 701 702 public: 703 class DefaultLoader: public QScxmlCompiler::Loader 704 { 705 public: 706 DefaultLoader(); 707 QByteArray load(const QString &name, 708 const QString &baseDir, 709 QStringList *errors) override final; 710 }; 711 712 private: 713 bool checkAttributes(const QXmlStreamAttributes &attributes, QScxmlCompilerPrivate::ParserState::Kind kind); 714 ParserState ¤t(); 715 ParserState &previous(); 716 bool hasPrevious() const; 717 718 private: 719 QString m_fileName; 720 QSet<QString> m_allIds; 721 722 QScopedPointer<DocumentModel::ScxmlDocument> m_doc; 723 DocumentModel::StateContainer *m_currentState; 724 DefaultLoader m_defaultLoader; 725 QScxmlCompiler::Loader *m_loader; 726 727 QXmlStreamReader *m_reader; 728 QVector<ParserState> m_stack; 729 QVector<QScxmlError> m_errors; 730 }; 731 732 QT_END_NAMESPACE 733 734 #endif // QSCXMLCOMPILER_P_H 735