diff --git a/plugins/robots/generators/ev3/ev3GeneratorBase/include/ev3GeneratorBase/ev3GeneratorFactory.h b/plugins/robots/generators/ev3/ev3GeneratorBase/include/ev3GeneratorBase/ev3GeneratorFactory.h index bff76dce3a..fcb277bb57 100644 --- a/plugins/robots/generators/ev3/ev3GeneratorBase/include/ev3GeneratorBase/ev3GeneratorFactory.h +++ b/plugins/robots/generators/ev3/ev3GeneratorBase/include/ev3GeneratorBase/ev3GeneratorFactory.h @@ -29,6 +29,7 @@ class ROBOTS_EV3_GENERATOR_BASE_EXPORT Ev3GeneratorFactory : public generatorBas , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName); ~Ev3GeneratorFactory() override; diff --git a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.cpp b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.cpp index 23fc4596c4..253b8929e9 100644 --- a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.cpp +++ b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.cpp @@ -20,9 +20,10 @@ Ev3GeneratorCustomizer::Ev3GeneratorCustomizer(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks) - : mFactory(repo, errorReporter, robotModelManager, luaProcessor, generatorName) + : mFactory(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager, generatorName) , mSupportsSwitchUnstableToBreaks(supportsSwitchUnstableToBreaks) { } diff --git a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.h b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.h index 70e761b1dc..401b53be64 100644 --- a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.h +++ b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorCustomizer.h @@ -27,6 +27,7 @@ class Ev3GeneratorCustomizer : public generatorBase::GeneratorCustomizer , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks); diff --git a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorFactory.cpp b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorFactory.cpp index fbd18410f1..78bb0380e3 100644 --- a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorFactory.cpp +++ b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3GeneratorFactory.cpp @@ -53,8 +53,9 @@ Ev3GeneratorFactory::Ev3GeneratorFactory(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName) - : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor) + : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager) , mGeneratorName(generatorName) , mMailboxes({":/" + mGeneratorName + "/templates"}) { diff --git a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3MasterGeneratorBase.cpp b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3MasterGeneratorBase.cpp index 5d90020eae..8d40f72f76 100644 --- a/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3MasterGeneratorBase.cpp +++ b/plugins/robots/generators/ev3/ev3GeneratorBase/src/ev3MasterGeneratorBase.cpp @@ -32,8 +32,8 @@ Ev3MasterGeneratorBase::Ev3MasterGeneratorBase(const qrRepo::RepoApi &repo generatorBase::GeneratorCustomizer *Ev3MasterGeneratorBase::createCustomizer() { - return new Ev3GeneratorCustomizer(mRepo, mErrorReporter, mRobotModelManager, *createLuaProcessor(), - mGeneratorName, supportsSwitchUnstableToBreaks()); + return new Ev3GeneratorCustomizer(mRepo, mErrorReporter, mRobotModelManager, *createLuaProcessor() + , *mReadableLabelManager, mGeneratorName, supportsSwitchUnstableToBreaks()); } void Ev3MasterGeneratorBase::beforeGeneration() diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.cpp b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.cpp index 018e69920c..b96da7c204 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.cpp +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.cpp @@ -20,9 +20,10 @@ Ev3RbfGeneratorCustomizer::Ev3RbfGeneratorCustomizer(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks) - : mFactory(repo, errorReporter, robotModelManager, luaProcessor, generatorName) + : mFactory(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager, generatorName) , mSupportsSwitchUnstableToBreaks(supportsSwitchUnstableToBreaks) { } diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.h b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.h index 764d6582cc..09bd5a9062 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.h +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorCustomizer.h @@ -28,6 +28,7 @@ class Ev3RbfGeneratorCustomizer : public generatorBase::GeneratorCustomizer , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks); diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.cpp b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.cpp index 4d1708efb4..5b63354925 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.cpp +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.cpp @@ -22,8 +22,9 @@ Ev3RbfGeneratorFactory::Ev3RbfGeneratorFactory(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName) - : Ev3GeneratorFactory(repo, errorReporter, robotModelManager, luaProcessor, generatorName) + : Ev3GeneratorFactory(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager, generatorName) { } diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.h b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.h index 8c8e28e4a1..cdfd339fd3 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.h +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfGeneratorFactory.h @@ -27,6 +27,7 @@ class Ev3RbfGeneratorFactory : public Ev3GeneratorFactory , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName); generatorBase::simple::AbstractSimpleGenerator *labelGenerator(const qReal::Id &id diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfMasterGenerator.cpp b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfMasterGenerator.cpp index db188dec86..0a408248b1 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfMasterGenerator.cpp +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/ev3RbfMasterGenerator.cpp @@ -153,5 +153,5 @@ generatorBase::lua::LuaProcessor *Ev3RbfMasterGenerator::createLuaProcessor() GeneratorCustomizer *Ev3RbfMasterGenerator::createCustomizer() { return new Ev3RbfGeneratorCustomizer(mRepo, mErrorReporter - , mRobotModelManager, *createLuaProcessor(), mGeneratorName, supportsSwitchUnstableToBreaks()); + , mRobotModelManager, *createLuaProcessor(), *mReadableLabelManager, mGeneratorName, supportsSwitchUnstableToBreaks()); } diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/templates.qrc b/plugins/robots/generators/ev3/ev3RbfGenerator/templates.qrc index 98a5aa36e3..349136fe84 100644 --- a/plugins/robots/generators/ev3/ev3RbfGenerator/templates.qrc +++ b/plugins/robots/generators/ev3/ev3RbfGenerator/templates.qrc @@ -5,6 +5,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/initialNode.t templates/finalNodeMain.t templates/finalNodeSubprogram.t diff --git a/plugins/robots/generators/ev3/ev3RbfGenerator/templates/pass.t b/plugins/robots/generators/ev3/ev3RbfGenerator/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/generatorBase/generatorBase.pri b/plugins/robots/generators/generatorBase/generatorBase.pri index 956daa1cee..6ccbc16444 100644 --- a/plugins/robots/generators/generatorBase/generatorBase.pri +++ b/plugins/robots/generators/generatorBase/generatorBase.pri @@ -65,22 +65,26 @@ HEADERS += \ $$PWD/include/generatorBase/lua/reservedFunctionsConverter.h \ $$PWD/include/generatorBase/gotoControlFlowGenerator.h \ $$PWD/src/converters/dynamicPropertiesConverter.h \ + $$PWD/src/readableLabelManager.h \ + $$PWD/src/simpleGenerators/passGenerator.h \ + $$PWD/src/simpleGenerators/syntheticIfGenerator.h \ + $$PWD/src/simpleGenerators/syntheticVariableNameGenerator.h \ $$PWD/src/structuralControlFlowGenerator.h \ - $$PWD/src/structurizator.h \ + $$PWD/src/structurizer.h \ + $$PWD/src/structurizerNodes/breakStructurizerNode.h \ + $$PWD/src/structurizerNodes/continuationStructurizerNode.h \ + $$PWD/src/structurizerNodes/ifStructurizerNode.h \ + $$PWD/src/structurizerNodes/loopStructurizerNode.h \ + $$PWD/src/structurizerNodes/sequenceStructurizerNode.h \ + $$PWD/src/structurizerNodes/simpleStructurizerNode.h \ + $$PWD/src/structurizerNodes/structurizerNode.h \ + $$PWD/src/structurizerNodes/switchStructurizerNode.h \ HEADERS += \ - $$PWD/src/structurizatorNodes/intermediateStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/simpleStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/breakStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/ifStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/structurizatorNodeWithBreaks.h \ - $$PWD/src/structurizatorNodes/switchStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/blockStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/whileStructurizatorNode.h \ - $$PWD/src/structurizatorNodes/selfLoopStructurizatorNode.h \ SOURCES += \ + $$PWD/src/readableLabelManager.cpp \ $$PWD/src/robotsGeneratorPluginBase.cpp \ $$PWD/src/masterGeneratorBase.cpp \ $$PWD/src/generatorCustomizer.cpp \ @@ -88,6 +92,17 @@ SOURCES += \ $$PWD/src/robotsDiagramVisitor.cpp \ $$PWD/src/primaryControlFlowValidator.cpp \ $$PWD/src/generatorFactoryBase.cpp \ + $$PWD/src/simpleGenerators/passGenerator.cpp \ + $$PWD/src/simpleGenerators/syntheticIfGenerator.cpp \ + $$PWD/src/simpleGenerators/syntheticVariableNameGenerator.cpp \ + $$PWD/src/structurizerNodes/breakStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/continuationStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/ifStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/loopStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/sequenceStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/simpleStructurizerNode.cpp \ + $$PWD/src/structurizerNodes/structurizerNode.cpp \ + $$PWD/src/structurizerNodes/switchStructurizerNode.cpp \ $$PWD/src/templateParametrizedEntity.cpp \ $$PWD/src/parts/variables.cpp \ $$PWD/src/parts/subprograms.cpp \ @@ -113,7 +128,7 @@ SOURCES += \ $$PWD/src/gotoControlFlowGenerator.cpp \ $$PWD/src/converters/dynamicPropertiesConverter.cpp \ $$PWD/src/structuralControlFlowGenerator.cpp \ - $$PWD/src/structurizator.cpp \ + $$PWD/src/structurizer.cpp \ # Simple element generators & converters @@ -253,12 +268,3 @@ SOURCES += \ $$PWD/src/lua/precedenceConverter.cpp \ SOURCES += \ - $$PWD/src/structurizatorNodes/intermediateStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/simpleStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/breakStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/ifStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/structurizatorNodeWithBreaks.cpp \ - $$PWD/src/structurizatorNodes/switchStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/blockStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/whileStructurizatorNode.cpp \ - $$PWD/src/structurizatorNodes/selfLoopStructurizatorNode.cpp \ diff --git a/plugins/robots/generators/generatorBase/include/generatorBase/generatorFactoryBase.h b/plugins/robots/generators/generatorBase/include/generatorBase/generatorFactoryBase.h index 4d6cdd3dd9..d186ce69c7 100644 --- a/plugins/robots/generators/generatorBase/include/generatorBase/generatorFactoryBase.h +++ b/plugins/robots/generators/generatorBase/include/generatorBase/generatorFactoryBase.h @@ -42,6 +42,7 @@ class LuaProcessor; } class GeneratorCustomizer; +class ReadableLabelManager; /// This class must be inherited in each concrete generator. Implementation /// must specify every generator part (starting from simple block generators @@ -53,7 +54,8 @@ class ROBOTS_GENERATOR_EXPORT GeneratorFactoryBase : public QObject GeneratorFactoryBase(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager - , lua::LuaProcessor &luaProcessor); + , lua::LuaProcessor &luaProcessor + , ReadableLabelManager &readableLabelManager); virtual ~GeneratorFactoryBase(); @@ -97,6 +99,14 @@ class ROBOTS_GENERATOR_EXPORT GeneratorFactoryBase : public QObject , bool elseIsEmpty , bool needInverting); + /// Returns a pointer to a code generator for blocks with if semantics + virtual simple::AbstractSimpleGenerator *syntheticIfGenerator(const qReal::Id &id + , const QMap &ids + , GeneratorCustomizer &customizer + , bool elseIsEmpty + , QString syntheticCondition + , bool needInverting); + /// Returns a pointer to a code generator for infinite loops virtual simple::AbstractSimpleGenerator *infiniteLoopGenerator(const qReal::Id &id , GeneratorCustomizer &customizer); @@ -143,10 +153,18 @@ class ROBOTS_GENERATOR_EXPORT GeneratorFactoryBase : public QObject virtual simple::AbstractSimpleGenerator *continueGenerator(const qReal::Id &id , GeneratorCustomizer &customizer); + /// Returns a pointer to a code generator for 'pass' instruction + virtual simple::AbstractSimpleGenerator *passGenerator(const qReal::Id &id + , GeneratorCustomizer &customizer); + /// Returns a pointer to a code generator for goto label declaration virtual simple::AbstractSimpleGenerator *labelGenerator(const qReal::Id &id , GeneratorCustomizer &customizer); + /// Returns a pointer to a code generator for goto label declaration + virtual simple::AbstractSimpleGenerator *syntheticVariableNameGenerator(const qReal::Id &id + , GeneratorCustomizer &customizer); + /// Returns a pointer to a code generator for 'goto' instruction virtual simple::AbstractSimpleGenerator *gotoSimpleGenerator(const qReal::Id &id , GeneratorCustomizer &customizer); @@ -276,6 +294,7 @@ class ROBOTS_GENERATOR_EXPORT GeneratorFactoryBase : public QObject QScopedPointer mSensors; QScopedPointer mFunctions; QScopedPointer mDeviceVariables; + ReadableLabelManager &mReadableLabelManager; int mLoopGeneratorIndex { 0 }; }; diff --git a/plugins/robots/generators/generatorBase/include/generatorBase/masterGeneratorBase.h b/plugins/robots/generators/generatorBase/include/generatorBase/masterGeneratorBase.h index d0db8b7df2..b7ee74bef9 100644 --- a/plugins/robots/generators/generatorBase/include/generatorBase/masterGeneratorBase.h +++ b/plugins/robots/generators/generatorBase/include/generatorBase/masterGeneratorBase.h @@ -25,6 +25,8 @@ #include "templateParametrizedEntity.h" #include "primaryControlFlowValidator.h" +#include "src/readableLabelManager.h" + class QFileInfo; namespace utils { @@ -114,6 +116,9 @@ class ROBOTS_GENERATOR_EXPORT MasterGeneratorBase : public QObject, public Templ QString mProjectDir; int mCurInitialNodeNumber {}; const utils::ParserErrorReporter &mParserErrorReporter; + + /// Storage and generator for human-readable goto labels. + QScopedPointer mReadableLabelManager; }; } diff --git a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/ifNode.h b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/ifNode.h index afef75a224..66ce79e19b 100644 --- a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/ifNode.h +++ b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/ifNode.h @@ -26,6 +26,7 @@ class ROBOTS_GENERATOR_EXPORT IfNode : public ConditionalNode { public: explicit IfNode(const qReal::Id &idBinded, QObject *parent = nullptr); + explicit IfNode(QObject *parent = nullptr); ZoneNode *thenZone(); ZoneNode *elseZone(); @@ -33,14 +34,21 @@ class ROBOTS_GENERATOR_EXPORT IfNode : public ConditionalNode /// Will be called when both branches link to same block, making thus if statement unnesesary. void transformToSimple(); + void setSyntheticCondition(const QString &s, const QMap &l); + protected: QLinkedList children() const override; QString toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const override; private: + void init(); + ZoneNode *mThenZone; // Takes ownership ZoneNode *mElseZone; // Takes ownership - bool mIsSimple; + bool mIsSimple {false}; + bool mIsSynthetic; + QString mSyntheticCondition; + QMap mIdWasUsedBefore; }; } diff --git a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/simpleNode.h b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/simpleNode.h index f462c97382..4ac698c30b 100644 --- a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/simpleNode.h +++ b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/simpleNode.h @@ -33,6 +33,8 @@ class ROBOTS_GENERATOR_EXPORT SimpleNode : public NonZoneNode , breakNode , continueNode , gotoNode + , tempVariableNode + , passNode }; explicit SimpleNode(const qReal::Id &idBinded, QObject *parent = nullptr); @@ -41,6 +43,9 @@ class ROBOTS_GENERATOR_EXPORT SimpleNode : public NonZoneNode void bindToSyntheticConstruction(SyntheticBlockType type); static SimpleNode *createBreakNode(QObject *parent); + static SimpleNode *createPassNode(QObject *parent); + static SimpleNode *createSyntheticVariableNode(const qReal::Id &id, QObject *parent); + protected: QLinkedList children() const override; diff --git a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/switchNode.h b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/switchNode.h index 36e1410ee7..0b609d8a75 100644 --- a/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/switchNode.h +++ b/plugins/robots/generators/generatorBase/include/generatorBase/semanticTree/switchNode.h @@ -28,10 +28,10 @@ class ROBOTS_GENERATOR_EXPORT SwitchNode : public NonZoneNode explicit SwitchNode(const qReal::Id &idBinded, QObject *parent = nullptr); /// Adds new branch for the switch value (i.e. branch zone will be created for the given value). - void addBranch(const QString &value, SemanticNode * const node); + void addBranch(const QString &value); - /// Binds existing branch with the switch value (i.e. value will be binded with the parent zone of the node). - void mergeBranch(const QString &value, NonZoneNode * const node); + /// Binds existing branch with the switch value (i.e. value will be binded with zone node of the branch). + void mergeBranch(const QString &value, ZoneNode * const zone); /// Returns true if branches for this switch block were already merged. /// This can help to resolve confusion in case when one branch enter into the middle of another. @@ -43,6 +43,9 @@ class ROBOTS_GENERATOR_EXPORT SwitchNode : public NonZoneNode void setGenerateIfs(); + /// Returns branch zone node by guard value. + ZoneNode *branchZoneByValue(const QString &value); + protected: QLinkedList children() const override; QString toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const override; diff --git a/plugins/robots/generators/generatorBase/src/generatorFactoryBase.cpp b/plugins/robots/generators/generatorBase/src/generatorFactoryBase.cpp index ae44a5776e..5878077190 100644 --- a/plugins/robots/generators/generatorBase/src/generatorFactoryBase.cpp +++ b/plugins/robots/generators/generatorBase/src/generatorFactoryBase.cpp @@ -20,9 +20,11 @@ #include "simpleGenerators/nullGenerator.h" #include "simpleGenerators/commentElementGenerator.h" #include "simpleGenerators/ifElementGenerator.h" +#include "simpleGenerators/syntheticIfGenerator.h" #include "simpleGenerators/infiniteLoopGenerator.h" #include "simpleGenerators/forLoopGenerator.h" #include "simpleGenerators/whileLoopGenerator.h" +#include "simpleGenerators/syntheticVariableNameGenerator.h" #include "simpleGenerators/forkCallGenerator.h" #include "simpleGenerators/joinGenerator.h" #include "simpleGenerators/killThreadGenerator.h" @@ -49,6 +51,7 @@ #include "simpleGenerators/subprogramsSimpleGenerator.h" #include "simpleGenerators/breakGenerator.h" #include "simpleGenerators/continueGenerator.h" +#include "simpleGenerators/passGenerator.h" #include "simpleGenerators/labelGenerator.h" #include "simpleGenerators/gotoSimpleGenerator.h" #include "simpleGenerators/variableInitGenerator.h" @@ -95,11 +98,13 @@ using namespace kitBase::robotModel; GeneratorFactoryBase::GeneratorFactoryBase(const qrRepo::RepoApi &repo , ErrorReporterInterface &errorReporter , const RobotModelManagerInterface &robotModelManager - , lua::LuaProcessor &luaProcessor) + , lua::LuaProcessor &luaProcessor + , ReadableLabelManager &readableLabelManager) : mRepo(repo) , mErrorReporter(errorReporter) , mRobotModelManager(robotModelManager) , mLuaTranslator(luaProcessor) + , mReadableLabelManager(readableLabelManager) { } @@ -206,6 +211,14 @@ simple::AbstractSimpleGenerator *GeneratorFactoryBase::ifGenerator(const Id &id , bool needInverting) RETURN_GENERATOR_PTR(IfElementGenerator, (mRepo, customizer, id, elseIsEmpty, needInverting, this)) +simple::AbstractSimpleGenerator *GeneratorFactoryBase::syntheticIfGenerator(const Id &id + , const QMap &ids + , GeneratorCustomizer &customizer + , bool elseIsEmpty + , QString syntheticCondition + , bool needInverting) +RETURN_GENERATOR_PTR(SyntheticIfGenerator, (mRepo, customizer, ids, elseIsEmpty, syntheticCondition + , id, needInverting, mReadableLabelManager, this)) simple::AbstractSimpleGenerator *GeneratorFactoryBase::infiniteLoopGenerator(const Id &id , GeneratorCustomizer &customizer) @@ -315,10 +328,18 @@ simple::AbstractSimpleGenerator *GeneratorFactoryBase::continueGenerator(const I , GeneratorCustomizer &customizer) RETURN_GENERATOR_PTR(ContinueGenerator, (mRepo, customizer, id, this)) +simple::AbstractSimpleGenerator *GeneratorFactoryBase::passGenerator(const Id &id + , GeneratorCustomizer &customizer) +RETURN_GENERATOR_PTR(PassGenerator, (mRepo, customizer, id, this)) + AbstractSimpleGenerator *GeneratorFactoryBase::labelGenerator(const qReal::Id &id , GeneratorCustomizer &customizer) RETURN_GENERATOR_PTR(LabelGenerator, (mRepo, customizer, id, this)) +AbstractSimpleGenerator *GeneratorFactoryBase::syntheticVariableNameGenerator(const qReal::Id &id + , GeneratorCustomizer &customizer) +RETURN_GENERATOR_PTR(SyntheticVariableNameGenerator, (mRepo, customizer, id, mReadableLabelManager, this)) + AbstractSimpleGenerator *GeneratorFactoryBase::gotoSimpleGenerator(const qReal::Id &id , GeneratorCustomizer &customizer) RETURN_GENERATOR_PTR(GotoSimpleGenerator, (mRepo, customizer, id, this)) diff --git a/plugins/robots/generators/generatorBase/src/gotoControlFlowGenerator.cpp b/plugins/robots/generators/generatorBase/src/gotoControlFlowGenerator.cpp index 0a5dfe6a29..e103b8803f 100644 --- a/plugins/robots/generators/generatorBase/src/gotoControlFlowGenerator.cpp +++ b/plugins/robots/generators/generatorBase/src/gotoControlFlowGenerator.cpp @@ -100,7 +100,8 @@ void GotoControlFlowGenerator::visitSwitch(const Id &id, const QList & SwitchNode * const thisNode = static_cast(mSemanticTree->findNodeFor(id)); for (const LinkInfo &branch : links) { const QString value = mRepo.property(branch.linkId, "Guard").toString(); - thisNode->addBranch(value, produceGotoNode(branch.target)); + thisNode->addBranch(value); + thisNode->branchZoneByValue(value)->appendChild(produceGotoNode(branch.target)); produceNextNodeIfNeeded(branch, thisNode); } } diff --git a/plugins/robots/generators/generatorBase/src/masterGeneratorBase.cpp b/plugins/robots/generators/generatorBase/src/masterGeneratorBase.cpp index 21492ecd68..f07640d4b0 100644 --- a/plugins/robots/generators/generatorBase/src/masterGeneratorBase.cpp +++ b/plugins/robots/generators/generatorBase/src/masterGeneratorBase.cpp @@ -32,6 +32,7 @@ #include "generatorBase/parts/threads.h" #include "generatorBase/parts/sensors.h" #include "generatorBase/parts/initTerminateCodeGenerator.h" +#include "readableLabelManager.h" using namespace generatorBase; using namespace qReal; @@ -48,6 +49,7 @@ MasterGeneratorBase::MasterGeneratorBase(const qrRepo::RepoApi &repo , mTextLanguage(textLanguage) , mDiagram(diagramId) , mParserErrorReporter(parserErrorReporter) + , mReadableLabelManager(new ReadableLabelManager()) { } @@ -80,6 +82,8 @@ QString MasterGeneratorBase::generate(const QString &indentString) return QString(); } + mReadableLabelManager->reinit(); + beforeGeneration(); if (!QDir(mProjectDir).exists()) { QDir().mkpath(mProjectDir); diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.cpp b/plugins/robots/generators/generatorBase/src/readableLabelManager.cpp similarity index 74% rename from plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.cpp rename to plugins/robots/generators/generatorBase/src/readableLabelManager.cpp index e0bf94b1fe..5f52a101ce 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.cpp +++ b/plugins/robots/generators/generatorBase/src/readableLabelManager.cpp @@ -1,4 +1,4 @@ -/* Copyright 2017 QReal Research Group +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,14 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "gotoLabelManager.h" +#include "readableLabelManager.h" #include #include -using namespace pioneer::lua; +using namespace generatorBase; -QString GotoLabelManager::labelFor(const qReal::Id &id) +QString ReadableLabelManager::labelFor(const qReal::Id &id, const QString &prefix) { qReal::Id actualId = id; if (actualId.editor().startsWith("label_")) { @@ -34,25 +34,27 @@ QString GotoLabelManager::labelFor(const qReal::Id &id) return mLabels.value(actualId); } - const auto type = actualId.type(); + const auto type = prefix == "" + ? QString("%1_").arg(beautify(actualId.element())) + : prefix; if (mNodeTypesCount.contains(type)) { ++mNodeTypesCount[type]; } else { mNodeTypesCount.insert(type, 1); } - const auto label = beautify(QString("%1_%2").arg(actualId.element()).arg(mNodeTypesCount.value(type))); + const auto label = QString("%1%2").arg(type).arg(mNodeTypesCount.value(type)); mLabels.insert(actualId, label); return label; } -void GotoLabelManager::reinit() +void ReadableLabelManager::reinit() { mLabels.clear(); mNodeTypesCount.clear(); } -QString GotoLabelManager::beautify(const QString &label) +QString ReadableLabelManager::beautify(const QString &label) { QString result; for (QChar ch : label) { diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.h b/plugins/robots/generators/generatorBase/src/readableLabelManager.h similarity index 78% rename from plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.h rename to plugins/robots/generators/generatorBase/src/readableLabelManager.h index c9cde5bb41..8e2b322f95 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/generators/gotoLabelManager.h +++ b/plugins/robots/generators/generatorBase/src/readableLabelManager.h @@ -1,4 +1,4 @@ -/* Copyright 2017 QReal Research Group +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,15 @@ #include -namespace pioneer { -namespace lua { +namespace generatorBase { /// Class that stores and produces human-readable labels for goto statements. -class GotoLabelManager +class ReadableLabelManager { public: /// Returns existing or generates new label for a node with given id. - QString labelFor(const qReal::Id &id); + /// For new ids label starts with given prefix or uses node type. + QString labelFor(const qReal::Id &id, const QString &prefix = ""); /// Clears all stored labels. void reinit(); @@ -36,10 +36,8 @@ class GotoLabelManager /// Makes given string CAPS_WITH_UNDERSCORES. static QString beautify(const QString &label); - QHash mNodeTypesCount; + QHash mNodeTypesCount; QHash mLabels; - }; } -} diff --git a/plugins/robots/generators/generatorBase/src/semanticTree/ifNode.cpp b/plugins/robots/generators/generatorBase/src/semanticTree/ifNode.cpp index 2de67df26d..639ef07863 100644 --- a/plugins/robots/generators/generatorBase/src/semanticTree/ifNode.cpp +++ b/plugins/robots/generators/generatorBase/src/semanticTree/ifNode.cpp @@ -21,11 +21,24 @@ using namespace qReal; IfNode::IfNode(const Id &idBinded, QObject *parent) : ConditionalNode(idBinded, parent) - , mThenZone(new ZoneNode(this)) - , mElseZone(new ZoneNode(this)) - , mIsSimple(false) + , mIsSynthetic(false) { + init(); +} + +IfNode::IfNode(QObject *parent) + : ConditionalNode(qReal::Id(), parent) + , mIsSynthetic(true) +{ + init(); +} + +void IfNode::init() +{ + mThenZone = new ZoneNode(parent()); mThenZone->setParentNode(this); + + mElseZone = new ZoneNode(parent()); mElseZone->setParentNode(this); } @@ -44,6 +57,13 @@ void IfNode::transformToSimple() mIsSimple = true; } +void IfNode::setSyntheticCondition(const QString &s, const QMap &l) +{ + mIsSynthetic = true; + mSyntheticCondition = s; + mIdWasUsedBefore = l; +} + QString IfNode::toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const { if (mIsSimple) { @@ -55,7 +75,11 @@ QString IfNode::toStringImpl(GeneratorCustomizer &customizer, int indent, const } const bool elseIsEmpty = mElseZone->isEmpty(); - QString result = utils::StringUtils::addIndent(customizer.factory()-> + QString result = mIsSynthetic ? + utils::StringUtils::addIndent(customizer.factory()-> + syntheticIfGenerator(mId, mIdWasUsedBefore, customizer, elseIsEmpty + , mSyntheticCondition, mAddNotToCondition)->generate(), indent, indentString) + : utils::StringUtils::addIndent(customizer.factory()-> ifGenerator(mId, customizer, elseIsEmpty, mAddNotToCondition)->generate(), indent, indentString); const QString thenBlock = mThenZone->toString(customizer, indent + 1, indentString); diff --git a/plugins/robots/generators/generatorBase/src/semanticTree/simpleNode.cpp b/plugins/robots/generators/generatorBase/src/semanticTree/simpleNode.cpp index 88611e039a..16fa131515 100644 --- a/plugins/robots/generators/generatorBase/src/semanticTree/simpleNode.cpp +++ b/plugins/robots/generators/generatorBase/src/semanticTree/simpleNode.cpp @@ -32,12 +32,18 @@ QString SimpleNode::toStringImpl(GeneratorCustomizer &customizer, int indent, co case breakNode: return utils::StringUtils::addIndent(customizer.factory()->breakGenerator(mId , customizer)->generate(), indent, indentString); + case passNode: + return utils::StringUtils::addIndent(customizer.factory()->passGenerator(mId + , customizer)->generate(), indent, indentString); case continueNode: return utils::StringUtils::addIndent(customizer.factory()->continueGenerator(mId , customizer)->generate(), indent, indentString); case gotoNode: return utils::StringUtils::addIndent(customizer.factory()->gotoSimpleGenerator(mId , customizer)->generate(), indent, indentString); + case tempVariableNode: + return utils::StringUtils::addIndent(customizer.factory()->syntheticVariableNameGenerator(mId + , customizer)->generate(), indent, indentString); default: return utils::StringUtils::addIndent(customizer.factory()->simpleGenerator(mId , customizer)->generate(), indent, indentString); @@ -56,6 +62,20 @@ SimpleNode *SimpleNode::createBreakNode(QObject *parent) return breakNode; } +SimpleNode *SimpleNode::createPassNode(QObject *parent) +{ + SimpleNode *passNode = new SimpleNode(qReal::Id(), parent); + passNode->bindToSyntheticConstruction(SyntheticBlockType::passNode); + return passNode; +} + +SimpleNode *SimpleNode::createSyntheticVariableNode(const qReal::Id &id, QObject *parent) +{ + SimpleNode *varNode = new SimpleNode(id, parent); + varNode->bindToSyntheticConstruction(SyntheticBlockType::tempVariableNode); + return varNode; +} + QLinkedList SimpleNode::children() const { return QLinkedList(); diff --git a/plugins/robots/generators/generatorBase/src/semanticTree/switchNode.cpp b/plugins/robots/generators/generatorBase/src/semanticTree/switchNode.cpp index 53ab2d0adb..7b95990ac6 100644 --- a/plugins/robots/generators/generatorBase/src/semanticTree/switchNode.cpp +++ b/plugins/robots/generators/generatorBase/src/semanticTree/switchNode.cpp @@ -27,20 +27,17 @@ SwitchNode::SwitchNode(const Id &idBinded, QObject *parent) { } -void SwitchNode::addBranch(const QString &value, SemanticNode * const node) +void SwitchNode::addBranch(const QString &value) { ZoneNode * const zone = new ZoneNode(this); zone->setParentNode(this); bind(value, zone); - if (node) { - zone->appendChild(node); - } } -void SwitchNode::mergeBranch(const QString &value, NonZoneNode * const node) +void SwitchNode::mergeBranch(const QString &value, ZoneNode * const zone) { - Q_ASSERT(node); - bind(value, node->parentZone()); + Q_ASSERT(zone); + bind(value, zone); } bool SwitchNode::branchesMerged() const @@ -58,6 +55,18 @@ void SwitchNode::setGenerateIfs() mGenerateIfs = true; } + +ZoneNode *SwitchNode::branchZoneByValue(const QString &value) +{ + if (value.isEmpty()) { + return mDefaultBranch; + } + if (mBranches.contains(value)) { + return mBranches[value]; + } + return nullptr; +} + QString SwitchNode::toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const { QString result; diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.cpp similarity index 57% rename from plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.cpp rename to plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.cpp index bfccb7aed8..fe74f82846 100644 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.cpp +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.cpp @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,22 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "intermediateStructurizatorNode.h" +#include "passGenerator.h" -using namespace generatorBase; +using namespace generatorBase::simple; +using namespace qReal; -IntermediateStructurizatorNode::IntermediateStructurizatorNode(QObject *parent) - : QObject(parent) - , mHasBreakInside(false) - , mBreakWasAnalyzed(false) +PassGenerator::PassGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const Id &id + , QObject *parent) + : BindingGenerator(repo, customizer, id, "pass.t", QList(), parent) { } - -IntermediateStructurizatorNode::~IntermediateStructurizatorNode() -{ -} - -bool IntermediateStructurizatorNode::hasBreakInside() const -{ - return mHasBreakInside; -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.h similarity index 62% rename from plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.h rename to plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.h index 6e071fa683..a17aec8031 100644 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.h +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/passGenerator.h @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +14,20 @@ #pragma once -#include "intermediateStructurizatorNode.h" +#include "generatorBase/simpleGenerators/bindingGenerator.h" namespace generatorBase { +namespace simple { -class SimpleStructurizatorNode : public IntermediateStructurizatorNode +/// Generator for 'pass' construction +class PassGenerator : public BindingGenerator { - Q_OBJECT - public: - explicit SimpleStructurizatorNode(const qReal::Id &id, QObject *parent = nullptr); - - Type type() const; - qReal::Id firstId() const; - bool analyzeBreak(); - - qReal::Id id() const; -private: - const qReal::Id mId; + PassGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const qReal::Id &id + , QObject *parent = nullptr); }; } +} diff --git a/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.cpp b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.cpp new file mode 100644 index 0000000000..29e01f1572 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.cpp @@ -0,0 +1,53 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "syntheticIfGenerator.h" + +#include "generatorBase/generatorCustomizer.h" + +using namespace generatorBase::simple; + +SyntheticIfGenerator::SyntheticIfGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const QMap &useVariable + , bool elseIsEmpty + , const QString syntheticCondition + , const qReal::Id &id + , bool needInverting + , ReadableLabelManager &nameManager + , QObject *parent) + : AbstractSimpleGenerator(repo, customizer, id, parent) + , mUseVariable(useVariable) + , mSyntheticCondition(syntheticCondition) + , mElseIsEmpty(elseIsEmpty) + , mNeedInverting(needInverting) + , mNameManager(nameManager) +{ +} + +QString SyntheticIfGenerator::generate() +{ + QString result = mSyntheticCondition; + for (const qReal::Id &id : mUseVariable.keys()) { + if (mUseVariable[id]) { + result.replace(id.id(), mNameManager.labelFor(id, "__temp_")); + } else { + result.replace(id.id(), mRepo.property(id, "Condition").toString()); + } + } + QString finalResult = customizer().factory()->boolPropertyConverter(mUseVariable.firstKey() + , "Condition", mNeedInverting)->convert(result); + return readTemplate(mElseIsEmpty ? "conditional/if.t" : "conditional/ifElse.t") + .replace("@@CONDITION@@", finalResult); +} diff --git a/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.h b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.h new file mode 100644 index 0000000000..057089061f --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticIfGenerator.h @@ -0,0 +1,48 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "generatorBase/simpleGenerators/abstractSimpleGenerator.h" +#include "src/readableLabelManager.h" + +namespace generatorBase { +namespace simple { + +/// Generator for conditional construnctions +class SyntheticIfGenerator : public AbstractSimpleGenerator +{ +public: + SyntheticIfGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const QMap &useVariable + , bool elseIsEmpty + , const QString syntheticCondition + , const qReal::Id &id + , bool needInverting + , ReadableLabelManager &nameManager + , QObject *parent = nullptr); + + QString generate() override; + +private: + const QMap mUseVariable; + const QString mSyntheticCondition; + const bool mElseIsEmpty; + const bool mNeedInverting; + ReadableLabelManager &mNameManager; +}; + +} +} diff --git a/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.cpp b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.cpp new file mode 100644 index 0000000000..4cf04875b8 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.cpp @@ -0,0 +1,34 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "syntheticVariableNameGenerator.h" + +#include "generatorBase/generatorCustomizer.h" + +using namespace generatorBase; +using namespace qReal; + +simple::SyntheticVariableNameGenerator::SyntheticVariableNameGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const Id &id + , ReadableLabelManager &nameManager + , QObject *parent) + : BindingGenerator(repo, customizer, id, "function.t" + , { Binding::createStaticConverting("@@BODY@@" + , nameManager.labelFor(id, "__temp_") + "=" + + repo.property(id, repo.hasProperty(id, "Condition") ? "Condition" : "Expression").toString() + , customizer.factory()->functionBlockConverter(id, "Condition")) } + , parent) +{ +} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.h similarity index 58% rename from plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.h rename to plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.h index 9dcd65cd48..d0b710b832 100644 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.h +++ b/plugins/robots/generators/generatorBase/src/simpleGenerators/syntheticVariableNameGenerator.h @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +14,23 @@ #pragma once -#include "intermediateStructurizatorNode.h" +#include "generatorBase/simpleGenerators/bindingGenerator.h" +#include "src/readableLabelManager.h" namespace generatorBase { +namespace simple { -class SelfLoopStructurizatorNode : public IntermediateStructurizatorNode -{ - Q_OBJECT +//class ReadableLabelManager; +class SyntheticVariableNameGenerator : public BindingGenerator +{ public: - explicit SelfLoopStructurizatorNode(IntermediateStructurizatorNode *bodyNode, QObject *parent = nullptr); - - IntermediateStructurizatorNode *bodyNode() const; - - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mBodyNode; + SyntheticVariableNameGenerator(const qrRepo::RepoApi &repo + , GeneratorCustomizer &customizer + , const qReal::Id &id + , ReadableLabelManager &nameManager + , QObject *parent); }; } +} diff --git a/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.cpp b/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.cpp index 0c10f8a3e2..3ac59c5084 100644 --- a/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.cpp +++ b/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.cpp @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,6 @@ #include "structuralControlFlowGenerator.h" -#include "structurizatorNodes/intermediateStructurizatorNode.h" -#include "structurizatorNodes/blockStructurizatorNode.h" -#include "structurizatorNodes/breakStructurizatorNode.h" -#include "structurizatorNodes/ifStructurizatorNode.h" -#include "structurizatorNodes/structurizatorNodeWithBreaks.h" -#include "structurizatorNodes/selfLoopStructurizatorNode.h" -#include "structurizatorNodes/simpleStructurizatorNode.h" -#include "structurizatorNodes/switchStructurizatorNode.h" -#include "structurizatorNodes/whileStructurizatorNode.h" #include "generatorBase/parts/subprograms.h" #include "generatorBase/parts/threads.h" @@ -36,15 +27,11 @@ StructuralControlFlowGenerator::StructuralControlFlowGenerator(const qrRepo::Rep , PrimaryControlFlowValidator &validator , const Id &diagramId , QObject *parent - , bool isThisDiagramMain - , const Id &simpleId) + , bool isThisDiagramMain) : ControlFlowGeneratorBase(repo, errorReporter, customizer, validator, diagramId, parent, isThisDiagramMain) , mCanBeGeneratedIntoStructuredCode(true) - , mStructurizator(new Structurizator(this)) - , mVerticesNumber(0) - , mStartVertex(0) + , mStructurizer(new Structurizer(this)) , mIsGraphBeingConstructed(true) - , mFictiveId(simpleId) { } @@ -52,7 +39,7 @@ ControlFlowGeneratorBase *StructuralControlFlowGenerator::cloneFor(const Id &dia { StructuralControlFlowGenerator * const copy = new StructuralControlFlowGenerator(mRepo , mErrorReporter, mCustomizer, cloneForNewDiagram ? *mValidator.clone() : mValidator - , diagramId, parent(), false, mFictiveId); + , diagramId, parent(), false); return copy; } @@ -61,59 +48,36 @@ void StructuralControlFlowGenerator::beforeSearch() { } -void StructuralControlFlowGenerator::visit(const Id &id, QList &links) -{ - if (mFictiveId.isNull()) { - mFictiveId = id.sameTypeId(); - } - - mEdgesAndVerticesWereAdded = false; - - ControlFlowGeneratorBase::visit(id, links); - - if (!mEdgesAndVerticesWereAdded) { - appendEdgesAndVertices(id, links); - addVerticesInLoopBody(id, links); - } -} - -void StructuralControlFlowGenerator::afterVisit(const Id &id, QList &links) +void StructuralControlFlowGenerator::visitRegular(const Id &id, const QList &links) { if (!mIsGraphBeingConstructed) { + ControlFlowGeneratorBase::visitRegular(id, links); return; } - if (isLoop(id)) { - mLoopNumbers.pop(); - - const QPair loopBranches = loopBranchesFor(id); - mVerticesInsideLoopBody.remove(mVertexNumber[loopBranches.first.target]); - } - - removeVerticesFromLoopBody(id, links); + appendEdgesAndVertices(id, links); } void StructuralControlFlowGenerator::visitConditional(const Id &id, const QList &links) { - Q_UNUSED(id) Q_UNUSED(links) + const QPair ifBranches = ifBranchesFor(id); + + appendEdgesAndVertices(id, {ifBranches.first}); + appendEdgesAndVertices(id, {ifBranches.second}); } void StructuralControlFlowGenerator::visitLoop(const Id &id, const QList &links) { + Q_UNUSED(links) if (!mIsGraphBeingConstructed) { return; } - appendEdgesAndVertices(id, links); - addVerticesInLoopBody(id, links); - - mEdgesAndVerticesWereAdded = true; - - mLoopNumbers.push(mVertexNumber[id]); - const QPair loopBranches = loopBranchesFor(id); - mVerticesInsideLoopBody.insert(mVertexNumber[loopBranches.first.target]); + + appendEdgesAndVertices(id, {loopBranches.first}); + appendEdgesAndVertices(id, {loopBranches.second}); } void StructuralControlFlowGenerator::visitPreconditionalLoop(const Id &id, const QList &links) @@ -123,14 +87,24 @@ void StructuralControlFlowGenerator::visitPreconditionalLoop(const Id &id, const void StructuralControlFlowGenerator::visitSwitch(const Id &id, const QList &links) { - Q_UNUSED(id) - Q_UNUSED(links) + LinkInfo defaultLink; + for (auto &link : links) { + if (mRepo.property(link.linkId, "Guard").toString() == "") { + defaultLink = link; + } + } + for (auto &link : links) { + if (link.target == defaultLink.target) { + continue; + } + appendEdgesAndVertices(id, {link}); + } + appendEdgesAndVertices(id, {defaultLink}); } void StructuralControlFlowGenerator::visitUnknown(const Id &id, const QList &links) { - Q_UNUSED(id) - Q_UNUSED(links) + appendEdgesAndVertices(id, links); } void StructuralControlFlowGenerator::afterSearch() @@ -144,21 +118,23 @@ bool StructuralControlFlowGenerator::cantBeGeneratedIntoStructuredCode() const void StructuralControlFlowGenerator::performGeneration() { + mStartVertex = mSemanticTree->initialBlock(); + mIsGraphBeingConstructed = true; ControlFlowGeneratorBase::performGeneration(); - IntermediateStructurizatorNode *tree = mStructurizator->performStructurization(mIds - , mStartVertex, mFollowers, mVertexNumber, mVerticesNumber); - - if (tree) { - obtainSemanticTree(tree); - mIsGraphBeingConstructed = false; - ControlFlowGeneratorBase::performGeneration(); - } else { - mCanBeGeneratedIntoStructuredCode = false; - } - - if (!mCanBeGeneratedIntoStructuredCode) { - mSemanticTree = nullptr; + StructurizerNode *tree = mStructurizer->performStructurization(mIds + , mStartVertex, mFollowers); + QMap numberOfOccurrences; + for (const auto &e : mIds) { + if (mFollowers[e].size() > 1) { + numberOfOccurrences[e] = tree->numberOfConditionCalculating(e); + } } + QSet alreadyCalculated; + auto zone = new ZoneNode(mSemanticTree); + makeSemanticTree(tree, zone, numberOfOccurrences, alreadyCalculated); + mSemanticTree->setRoot(zone); + mIsGraphBeingConstructed = false; + ControlFlowGeneratorBase::performGeneration(); } void StructuralControlFlowGenerator::registerOtherThreads(const Id &id, const QList &threads @@ -177,363 +153,154 @@ void StructuralControlFlowGenerator::registerTerminatingThreads(const Id &id, pa } } -void StructuralControlFlowGenerator::obtainSemanticTree(IntermediateStructurizatorNode *root) +void StructuralControlFlowGenerator::makeSemanticTree(StructurizerNode *nodes, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - root->analyzeBreak(); - mSemanticTree->setRoot(transformNode(root)); -} - -void StructuralControlFlowGenerator::checkAndAppendBlock(ZoneNode *zone, IntermediateStructurizatorNode *node) -{ - if (node->type() == IntermediateStructurizatorNode::simple) { - SimpleStructurizatorNode *simpleNode = static_cast(node); - - switch (semanticsOf(simpleNode->id())) { - case enums::semantics::conditionalBlock: - case enums::semantics::switchBlock: - break; - default: - zone->appendChild(transformSimple(simpleNode)); + if (nodes != nullptr && nodes->type() == StructurizerNode::Type::sequence) { + for (auto &s : static_cast(nodes)->children()) { + switch (s->type()) { + case StructurizerNode::Type::simple: { + addSimple(s, zone, numberOfOccurrences, alreadyCalculated); + break; + } + case StructurizerNode::Type::breakFromLoop: { + addBreak(s, zone, numberOfOccurrences, alreadyCalculated); + break; + } + case StructurizerNode::Type::loop: { + addLoop(s, zone, numberOfOccurrences, alreadyCalculated); + break; + } + case StructurizerNode::Type::ifThenElse: { + addIf(s, zone, numberOfOccurrences, alreadyCalculated); + break; + } + case StructurizerNode::Type::switchCase: { + addSwitch(s, zone, numberOfOccurrences, alreadyCalculated); + break; + } + default: {qDebug() << "CONTINUATION IN FINAL TREE"; return;} + } } - } else { - zone->appendChild(transformNode(node)); - } + } else qDebug() << "that shouldn't happen too"; } -SemanticNode *StructuralControlFlowGenerator::transformNode(IntermediateStructurizatorNode *node) -{ - switch (node->type()) { - case IntermediateStructurizatorNode::Type::simple: { - SimpleStructurizatorNode *simpleNode = static_cast(node); - return transformSimple(simpleNode); - } - - case IntermediateStructurizatorNode::Type::block: { - BlockStructurizatorNode *blockNode = static_cast(node); - return transformBlock(blockNode); - } - - case IntermediateStructurizatorNode::Type::ifThenElseCondition: { - IfStructurizatorNode *ifNode = static_cast(node); - return transformIfThenElse(ifNode); - } - - case IntermediateStructurizatorNode::Type::switchCondition: { - SwitchStructurizatorNode *switchNode = static_cast(node); - return transformSwitch(switchNode); - } - - case IntermediateStructurizatorNode::Type::infiniteloop: { - SelfLoopStructurizatorNode *selfLoopNode = static_cast(node); - return transformSelfLoop(selfLoopNode); - } - - case IntermediateStructurizatorNode::Type::whileloop: { - WhileStructurizatorNode *whileNode = static_cast(node); - return transformWhileLoop(whileNode); - } - - case IntermediateStructurizatorNode::Type::breakNode: { - return transformBreakNode(); - } - - case IntermediateStructurizatorNode::Type::nodeWithBreaks: { - return createConditionWithBreaks(static_cast(node)); - } - - default: - mCanBeGeneratedIntoStructuredCode = false; - return mSemanticTree->produceSimple(); - } -} -SemanticNode *StructuralControlFlowGenerator::transformSimple(SimpleStructurizatorNode *simpleNode) +void StructuralControlFlowGenerator::addSimple(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - return mSemanticTree->produceNodeFor(simpleNode->id()); + Q_UNUSED(numberOfOccurrences) + Q_UNUSED(alreadyCalculated) + zone->appendChild(mSemanticTree->produceNodeFor(node->id())); } -SemanticNode *StructuralControlFlowGenerator::transformBlock(BlockStructurizatorNode *blockNode) +void StructuralControlFlowGenerator::addBreak(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - ZoneNode *zone = new ZoneNode(mSemanticTree); - checkAndAppendBlock(zone, blockNode->firstNode()); - checkAndAppendBlock(zone, blockNode->secondNode()); - - return zone; + Q_UNUSED(node) + Q_UNUSED(numberOfOccurrences) + Q_UNUSED(alreadyCalculated) + zone->appendChild(SimpleNode::createBreakNode(mSemanticTree)); } -SemanticNode *StructuralControlFlowGenerator::transformIfThenElse(IfStructurizatorNode *ifNode) +void StructuralControlFlowGenerator::addSwitch(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - if (ifNode->condition()->type() == IntermediateStructurizatorNode::nodeWithBreaks) { - StructurizatorNodeWithBreaks *nodeWithBreaks = - static_cast(ifNode->condition()); - nodeWithBreaks->setRestBranches({ifNode->thenBranch(), ifNode->elseBranch()}); - return createConditionWithBreaks(nodeWithBreaks); + auto switchElement = static_cast(node); + if (numberOfOccurrences[switchElement->id()] > 1) { + zone->appendChild(SimpleNode::createSyntheticVariableNode(switchElement->id(), mSemanticTree)); + alreadyCalculated.insert(switchElement->id()); } - const qReal::Id conditionId = ifNode->condition()->firstId(); - - switch (semanticsOf(conditionId)) { - - case enums::semantics::conditionalBlock: { - return createSemanticIfNode(conditionId, ifNode->thenBranch(), ifNode->elseBranch()); + auto switchNode = static_cast(mSemanticTree->produceNodeFor(switchElement->id())); + if (switchElement->hasBreakOnUpperLevel()) { + switchNode->setGenerateIfs(); } + zone->appendChild(switchNode); - case enums::semantics::switchBlock: { - QList branches = { ifNode->thenBranch() }; - - if (ifNode->elseBranch()) { - branches.append(ifNode->elseBranch()); - } - - return createSemanticSwitchNode(conditionId, branches, ifNode->hasBreakInside()); - } + QMap addedBranches; + for (const Id &link : mRepo.outgoingLinks(switchElement->id())) { + const QString value = mRepo.property(link, "Guard").toString(); + const Id targetId = mRepo.otherEntityFromLink(link, switchElement->id()); - case enums::semantics::preconditionalLoopBlock: - case enums::semantics::loopBlock : { - if ((ifNode->exit() && ifNode->elseBranch() && ifNode->exit()->firstId() == ifNode->firstId()) - || (!ifNode->exit() && ifNode->elseBranch())) { - ZoneNode *zone = new ZoneNode(mSemanticTree); - const qReal::Id loopCondition = ifNode->condition()->firstId(); - LoopNode *innerLoop = mSemanticTree->produceLoop(loopCondition); - - const QPair loopBranches = loopBranchesFor(loopCondition); - IntermediateStructurizatorNode *restBranch = ifNode->thenBranch(); - - if (ifNode->thenBranch()->firstId() == loopBranches.first.target) { - innerLoop->bodyZone()->appendChild(transformNode(ifNode->thenBranch())); - restBranch = ifNode->elseBranch(); + if (addedBranches.contains(targetId)) { + ZoneNode * const targetZone = addedBranches[targetId]; + switchNode->mergeBranch(value, targetZone); + } else { + switchNode->addBranch(value); + ZoneNode *zoneForBranch = switchNode->branchZoneByValue(value); + addedBranches[targetId] = zoneForBranch; + StructurizerNode *branchElement = nullptr; + if (targetId == (switchElement->defaultBranch().first)) { + branchElement = switchElement->defaultBranch().second; } else { - innerLoop->bodyZone()->appendChild(transformNode(ifNode->elseBranch())); + branchElement = switchElement->branches().value(targetId); } - - zone->appendChild(innerLoop); - zone->appendChild(transformNode(restBranch)); - return zone; - } - } - - default: - break; - } - - mCanBeGeneratedIntoStructuredCode = false; - return mSemanticTree->produceSimple(); -} - -SemanticNode *StructuralControlFlowGenerator::transformSelfLoop(SelfLoopStructurizatorNode *selfLoopNode) -{ - LoopNode *semanticLoop = mSemanticTree->produceLoop(); - semanticLoop->bodyZone()->appendChild(transformNode(selfLoopNode->bodyNode())); - return semanticLoop; -} - -SemanticNode *StructuralControlFlowGenerator::transformWhileLoop(WhileStructurizatorNode *whileNode) -{ - IntermediateStructurizatorNode *headNode = whileNode->headNode(); - IntermediateStructurizatorNode *bodyNode = whileNode->bodyNode(); - IntermediateStructurizatorNode *exitNode = whileNode->exitNode(); - - LoopNode *semanticLoop = nullptr; - const qReal::Id conditionId = headNode->firstId(); - - if (headNode->type() == IntermediateStructurizatorNode::Type::simple) { - switch (semanticsOf(conditionId)) { - case enums::semantics::conditionalBlock: { - if (ifBranchesFor(conditionId).first.target == bodyNode->firstId()) { - semanticLoop = mSemanticTree->produceLoop(conditionId); - } else { - semanticLoop = mSemanticTree->produceLoop(); - IfNode *conditionNode = mSemanticTree->produceConditional(conditionId); - conditionNode->thenZone()->appendChild(SimpleNode::createBreakNode(mSemanticTree)); - semanticLoop->bodyZone()->appendChild(conditionNode); + makeSemanticTree(branchElement, zoneForBranch, numberOfOccurrences, alreadyCalculated); + if (zoneForBranch->children().size() == 0) { + zoneForBranch->appendChild(SimpleNode::createPassNode(mSemanticTree)); } - - semanticLoop->bodyZone()->appendChild(transformNode(bodyNode)); - return semanticLoop; - } - - case enums::semantics::preconditionalLoopBlock: - case enums::semantics::loopBlock: { - semanticLoop = mSemanticTree->produceLoop(conditionId); - semanticLoop->bodyZone()->appendChild(transformNode(bodyNode)); - return semanticLoop; } - - case enums::semantics::switchBlock: { - StructurizatorNodeWithBreaks *nodeWithBreaks = new StructurizatorNodeWithBreaks(headNode - , { new BreakStructurizatorNode(exitNode->firstId(), mStructurizator) }, mStructurizator); - nodeWithBreaks->setRestBranches( { bodyNode } ); - - semanticLoop = mSemanticTree->produceLoop(); - semanticLoop->bodyZone()->appendChild(createConditionWithBreaks(nodeWithBreaks)); - return semanticLoop; - } - - default: - break; - } - } else if (headNode->type() == IntermediateStructurizatorNode::Type::nodeWithBreaks - && isLoop(conditionId)) { - StructurizatorNodeWithBreaks *nodeWitBreaks = static_cast(headNode); - if (nodeWitBreaks->exitBranches().size() != 1 || - nodeWitBreaks->exitBranches().first()->type() == IntermediateStructurizatorNode::block) { - mCanBeGeneratedIntoStructuredCode = false; - return mSemanticTree->produceSimple(); - } else { - semanticLoop = mSemanticTree->produceLoop(conditionId); - semanticLoop->bodyZone()->appendChild(transformNode(bodyNode)); - return semanticLoop; - } - } - - semanticLoop = mSemanticTree->produceLoop(); - semanticLoop->bodyZone()->appendChild(transformNode(headNode)); - semanticLoop->bodyZone()->appendChild(transformNode(bodyNode)); - return semanticLoop; -} - -SemanticNode *StructuralControlFlowGenerator::transformSwitch(SwitchStructurizatorNode *switchNode) -{ - const qReal::Id &conditionId = switchNode->condition()->firstId(); - const QList branches = switchNode->branches(); - - if (switchNode->condition()->type() == IntermediateStructurizatorNode::nodeWithBreaks) { - StructurizatorNodeWithBreaks *nodeWithBreaks = - static_cast(switchNode->condition()); - nodeWithBreaks->setRestBranches(branches); - return createConditionWithBreaks(nodeWithBreaks); } - - if (semanticsOf(conditionId) == enums::semantics::switchBlock) { - return createSemanticSwitchNode(conditionId, branches, switchNode->hasBreakInside()); - } - - mCanBeGeneratedIntoStructuredCode = false; - return mSemanticTree->produceSimple(); -} - -SemanticNode *StructuralControlFlowGenerator::transformBreakNode() -{ - return semantics::SimpleNode::createBreakNode(mSemanticTree); } -SemanticNode *StructuralControlFlowGenerator::createConditionWithBreaks(StructurizatorNodeWithBreaks *nodeWithBreaks) +void StructuralControlFlowGenerator::addIf(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - const qReal::Id conditionId = nodeWithBreaks->firstId(); - - const QList exitBranches = nodeWithBreaks->exitBranches(); - const QList restBranches = nodeWithBreaks->restBranches(); - - switch(semanticsOf(conditionId)) { - case enums::semantics::conditionalBlock: { - return createSemanticIfNode(conditionId, exitBranches.first(), nullptr); - } - - case enums::semantics::switchBlock: { - const QList allBranches = restBranches + exitBranches; - return createSemanticSwitchNode(conditionId, allBranches, true); - } - - case enums::semantics::preconditionalLoopBlock: - case enums::semantics::loopBlock: { - if (exitBranches.size() != 1 || - exitBranches.first()->type() == IntermediateStructurizatorNode::Type::breakNode) { - break; + auto ifElement = static_cast(node); + QMap idWasUsed; + for (auto &x : numberOfOccurrences.keys()) { //todo in topological order + if (ifElement->condition()->numberOfFirstVertex(x) > 0) { + if (!alreadyCalculated.contains(x) && numberOfOccurrences[x] > 1) { + zone->appendChild(SimpleNode::createSyntheticVariableNode(x, mSemanticTree)); + alreadyCalculated.insert(x); + } + idWasUsed[x] = alreadyCalculated.contains(x); } - - LoopNode *loopNode = mSemanticTree->produceLoop(conditionId); - loopNode->bodyZone()->appendChild(transformNode(exitBranches.first())); - return loopNode; } - - default: - break; - + auto ifNode = mSemanticTree->produceConditional(); + ifNode->setSyntheticCondition(syntheticConditionToString(ifElement->condition()), idWasUsed); + zone->appendChild(ifNode); + if (static_cast(ifElement->thenBranch())->children().size() == 0) { + ifNode->invertCondition(); + makeSemanticTree(ifElement->elseBranch(), ifNode->thenZone(), numberOfOccurrences, alreadyCalculated); + } else { + makeSemanticTree(ifElement->thenBranch(), ifNode->thenZone(), numberOfOccurrences, alreadyCalculated); + makeSemanticTree(ifElement->elseBranch(), ifNode->elseZone(), numberOfOccurrences, alreadyCalculated); } - - mCanBeGeneratedIntoStructuredCode = false; - return mSemanticTree->produceSimple(); } -SemanticNode *StructuralControlFlowGenerator::createSemanticIfNode(const Id &conditionId - , IntermediateStructurizatorNode *thenNode - , IntermediateStructurizatorNode *elseNode) +void StructuralControlFlowGenerator::addLoop(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated) { - IfNode *semanticIf = mSemanticTree->produceConditional(conditionId); - const QPair links = ifBranchesFor(conditionId); - - if (links.first.target != thenNode->firstId()) { - if (elseNode) { - IntermediateStructurizatorNode *tmp = thenNode; - thenNode = elseNode; - elseNode = tmp; - } else { - semanticIf->invertCondition(); + auto loopElement = static_cast(node); + LoopNode *loopNode = nullptr; + if (loopElement->id() == Id()) { + loopNode = mSemanticTree->produceLoop(); + } else { + loopNode = mSemanticTree->produceLoop(node->id()); + if (loopElement->isInverted()) { + loopNode->invertCondition(); } } - - semanticIf->thenZone()->appendChild(transformNode(thenNode)); - - if (elseNode) { - semanticIf->elseZone()->appendChild(transformNode(elseNode)); + zone->appendChild(loopNode); + makeSemanticTree(loopElement->body(), loopNode->bodyZone(), numberOfOccurrences, alreadyCalculated); + if (loopNode->bodyZone()->children().size() == 0) { + loopNode->bodyZone()->appendChild(SimpleNode::createPassNode(mSemanticTree)); } - - return semanticIf; } -SemanticNode *StructuralControlFlowGenerator::createSemanticSwitchNode(const Id &conditionId - , const QList &branches, bool generateIfs) -{ - SwitchNode *semanticSwitch = mSemanticTree->produceSwitch(conditionId); - - QMap visitedBranch; - - for (const qReal::Id &link : mRepo.outgoingLinks(conditionId)) { - const QString expression = mRepo.property(link, "Guard").toString(); - const qReal::Id otherVertex = mRepo.otherEntityFromLink(link, conditionId); - - if (visitedBranch.contains(otherVertex)) { - NonZoneNode * const target = static_cast(visitedBranch[otherVertex]); - semanticSwitch->mergeBranch(expression, target); - } else { - bool branchNodeWasFound = false; - SemanticNode *semanticNodeForBranch = nullptr; - for (IntermediateStructurizatorNode *branchNode : branches) { - if (branchNode->firstId() == otherVertex) { - semanticNodeForBranch = transformNode(branchNode); - branchNodeWasFound = true; - break; - } - } - - if (!branchNodeWasFound) { - semanticNodeForBranch = mSemanticTree->produceSimple(); - } - - semanticSwitch->addBranch(expression, semanticNodeForBranch); - visitedBranch[otherVertex] = semanticNodeForBranch; - } - } - - if (generateIfs) { - semanticSwitch->setGenerateIfs(); - } - - return semanticSwitch; -} void StructuralControlFlowGenerator::appendVertex(const Id &vertex) { mIds.insert(vertex); - mVerticesNumber++; - mVertexNumber[vertex] = mVerticesNumber; } void StructuralControlFlowGenerator::addEdgeIntoGraph(const Id &from, const Id &to) { - int numberFrom = mVertexNumber[from]; - int numberTo = mVertexNumber[to]; - mFollowers[numberFrom].insert(numberTo); + if (!mFollowers[from].contains(to)) { + mFollowers[from].append(to); + } } void StructuralControlFlowGenerator::appendEdgesAndVertices(const Id &vertex, const QList &links) @@ -546,57 +313,43 @@ void StructuralControlFlowGenerator::appendEdgesAndVertices(const Id &vertex, co appendVertex(vertex); } - if (!mStartVertex) { - mStartVertex = mVertexNumber[vertex]; - } - for (const LinkInfo &link : links) { - const qReal::Id otherVertex = link.target; - + const Id otherVertex = link.target; if (!mIds.contains(otherVertex)) { - if (isLoop(otherVertex)) { - const qReal::Id loopHeader = mFictiveId.sameTypeId(); - mAdditionalVertices.push_back(loopHeader); - appendVertex(loopHeader); - appendVertex(otherVertex); - addEdgeIntoGraph(vertex, loopHeader); - addEdgeIntoGraph(loopHeader, otherVertex); - mLoopHeader[mVertexNumber[otherVertex]] = mVertexNumber[loopHeader]; - } else { - appendVertex(otherVertex); - addEdgeIntoGraph(vertex, otherVertex); + appendVertex(otherVertex); + } + addEdgeIntoGraph(vertex, otherVertex); + } +} + +QString StructuralControlFlowGenerator::syntheticConditionToString(StructurizerNode::ConditionTree *tree) +{ + QString result; + if (tree->isValue()) { + auto head = tree->value().first; + auto target = tree->value().second; + if (mCustomizer.semanticsOf(head) == enums::semantics::conditionalBlock) { + //it is if + result = head.id(); + } else if (mCustomizer.semanticsOf(head) == enums::semantics::switchBlock) { + //it is switch + QList cases; + for (auto &link : mRepo.outgoingLinks(head)) { + if (mRepo.otherEntityFromLink(link, head) == target) { + QString guard = mRepo.property(link, "Guard").toString(); + cases << QString("(%1==%2)").arg(head.id(), guard); + } } + result = cases.join(" or "); } else { - if (!isLoop(otherVertex) || (mLoopNumbers.contains(mVertexNumber[otherVertex]) - && mVerticesInsideLoopBody.contains(mVertexNumber[vertex]))) { - addEdgeIntoGraph(vertex, otherVertex); - } else { - addEdgeIntoGraph(vertex, mVertexNumber.key(mLoopHeader[mVertexNumber[otherVertex]])); - } - } - } -} - -void StructuralControlFlowGenerator::addVerticesInLoopBody(const Id &vertex, const QList &links) -{ - if (mVerticesInsideLoopBody.contains(mVertexNumber[vertex])) { - for (const LinkInfo &link : links) { - mVerticesInsideLoopBody.insert(mVertexNumber[link.target]); - } - } -} - -void StructuralControlFlowGenerator::removeVerticesFromLoopBody(const Id &vertex, const QList &links) -{ - if (mVerticesInsideLoopBody.contains(mVertexNumber[vertex])) { - for (const LinkInfo &link : links) { - mVerticesInsideLoopBody.remove(mVertexNumber[link.target]); + //strange case + result = head.id(); } + } else { + result = tree->boolOperator() == StructurizerNode::ConditionTree::OR + ? "(@@1@@) or (@@2@@)" : "(@@1@@) and (@@2@@)"; + result.replace("@@1@@", syntheticConditionToString(tree->left())) + .replace("@@2@@", syntheticConditionToString(tree->right())); } -} - -bool StructuralControlFlowGenerator::isLoop(const Id &vertex) const -{ - auto s = semanticsOf(vertex); - return s == enums::semantics::loopBlock || s == enums::semantics::preconditionalLoopBlock; + return tree->isInverted() ? QString("not(%1)").arg(result) : result; } diff --git a/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.h b/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.h index 09f791c98b..d1e0028dd3 100644 --- a/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.h +++ b/plugins/robots/generators/generatorBase/src/structuralControlFlowGenerator.h @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,13 @@ #include "generatorBase/robotsGeneratorDeclSpec.h" #include "generatorBase/controlFlowGeneratorBase.h" #include "generatorBase/semanticTree/semanticTree.h" -#include "structurizator.h" +#include "structurizer.h" +#include "structurizerNodes/structurizerNode.h" +#include "structurizerNodes/ifStructurizerNode.h" +#include "structurizerNodes/loopStructurizerNode.h" +#include "structurizerNodes/simpleStructurizerNode.h" +#include "structurizerNodes/switchStructurizerNode.h" +#include "structurizerNodes/sequenceStructurizerNode.h" #include #include @@ -26,7 +32,7 @@ namespace generatorBase { /// Generates semantic tree in control-structured style. /// First we obtain control flow graph. -/// Then we are trying structurize such a graph with Structurizator. +/// Then we are trying structurize such a graph with Structurizer. /// If structurization was successfull then we are trying to transform /// control flow tree to Semantic Tree used for code generation. /// @@ -43,8 +49,7 @@ class ROBOTS_GENERATOR_EXPORT StructuralControlFlowGenerator : public ControlFlo , PrimaryControlFlowValidator &validator , const qReal::Id &diagramId , QObject *parent = 0 - , bool isThisDiagramMain = true - , const qReal::Id &simpleId = qReal::Id()); + , bool isThisDiagramMain = true); /// Implementation of clone operation for structural generator ControlFlowGeneratorBase *cloneFor(const qReal::Id &diagramId, bool cloneForNewDiagram) override; @@ -52,20 +57,14 @@ class ROBOTS_GENERATOR_EXPORT StructuralControlFlowGenerator : public ControlFlo void beforeSearch() override; /// functions for visiting Ids. While each visit we contruct graph. - void visit(const qReal::Id &id, QList &links) override; + void visitRegular(const qReal::Id &id, const QList &links) override; void visitConditional(const qReal::Id &id, const QList &links) override; void visitSwitch(const qReal::Id &id, const QList &links) override; void visitUnknown(const qReal::Id &id, QList const &links) override; - - /// We introduce fake-loop-preheader vertex incident to vertices not from loop body. - /// We remember vertices belonging to loop. void visitLoop(const qReal::Id &id, const QList &links) override; void visitPreconditionalLoop(const qReal::Id &id, const QList &links) override; - /// We clean old info about vertices belonging to some loop. - void afterVisit(const qReal::Id &id, QList &links) override; - /// This method can be used for semantic tree debug printing after all /// traversal stages. void afterSearch() override; @@ -91,58 +90,39 @@ class ROBOTS_GENERATOR_EXPORT StructuralControlFlowGenerator : public ControlFlo , bool fromMain) override; void performStructurization(); - void obtainSemanticTree(IntermediateStructurizatorNode *root); - - /// helper method for ZoneNode - void checkAndAppendBlock(semantics::ZoneNode *zone, IntermediateStructurizatorNode *node); - - /// transformation methods - semantics::SemanticNode *transformNode(IntermediateStructurizatorNode *node); - semantics::SemanticNode *transformSimple(SimpleStructurizatorNode *simpleNode); - semantics::SemanticNode *transformBlock(BlockStructurizatorNode *blockNode); - semantics::SemanticNode *transformIfThenElse(IfStructurizatorNode *ifNode); - semantics::SemanticNode *transformSelfLoop(SelfLoopStructurizatorNode *selfLoopNode); - semantics::SemanticNode *transformWhileLoop(WhileStructurizatorNode *whileNode); - semantics::SemanticNode *transformSwitch(SwitchStructurizatorNode *switchNode); - semantics::SemanticNode *transformBreakNode(); - - /// helper functions - semantics::SemanticNode *createConditionWithBreaks(StructurizatorNodeWithBreaks *nodeWithBreaks); - semantics::SemanticNode *createSemanticIfNode(const qReal::Id &conditionId - , IntermediateStructurizatorNode *thenNode - , IntermediateStructurizatorNode *elseNode); - - semantics::SemanticNode *createSemanticSwitchNode(const qReal::Id &conditionId - , const QList &branches - , bool generateIfs); + + void makeSemanticTree(StructurizerNode *nodes, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); + + void addSimple(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); + + void addBreak(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); + + void addIf(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); + + void addLoop(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); + + void addSwitch(StructurizerNode *node, semantics::ZoneNode *zone + , QMap &numberOfOccurrences, QSet &alreadyCalculated); /// methods for building graph void appendVertex(const qReal::Id &vertex); void addEdgeIntoGraph(const qReal::Id &from, const qReal::Id &to); void appendEdgesAndVertices(const qReal::Id &vertex, const QList &links); - /// methods for handling vertices belonging to loop body - void addVerticesInLoopBody(const qReal::Id &vertex, const QList &links); - void removeVerticesFromLoopBody(const qReal::Id &vertex, const QList &links); - - bool isLoop(const qReal::Id &vertex) const; + QString syntheticConditionToString(StructurizerNode::ConditionTree *tree); - QMap mTrees; bool mCanBeGeneratedIntoStructuredCode; - Structurizator *mStructurizator; + Structurizer *mStructurizer; - int mVerticesNumber; QSet mIds; - int mStartVertex; - QMap mVertexNumber; - QMap mLoopHeader; - QMap> mFollowers; + qReal::Id mStartVertex; + QMap> mFollowers; bool mIsGraphBeingConstructed; - QStack mLoopNumbers; - QSet mVerticesInsideLoopBody; - QVector mAdditionalVertices; - bool mEdgesAndVerticesWereAdded {}; - qReal::Id mFictiveId; }; } diff --git a/plugins/robots/generators/generatorBase/src/structurizator.cpp b/plugins/robots/generators/generatorBase/src/structurizator.cpp deleted file mode 100644 index 80233af907..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizator.cpp +++ /dev/null @@ -1,826 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "structurizator.h" - -#include - -#include "structurizatorNodes/intermediateStructurizatorNode.h" -#include "structurizatorNodes/blockStructurizatorNode.h" -#include "structurizatorNodes/breakStructurizatorNode.h" -#include "structurizatorNodes/ifStructurizatorNode.h" -#include "structurizatorNodes/structurizatorNodeWithBreaks.h" -#include "structurizatorNodes/selfLoopStructurizatorNode.h" -#include "structurizatorNodes/simpleStructurizatorNode.h" -#include "structurizatorNodes/switchStructurizatorNode.h" -#include "structurizatorNodes/whileStructurizatorNode.h" - -using namespace generatorBase; - -Structurizator::Structurizator(QObject *parent) - : QObject(parent) - , mVerticesNumber(1) - , mStartVertex(-1) - , mMaxPostOrderTime(-1) -{ -} - -IntermediateStructurizatorNode *Structurizator::performStructurization(const QSet &verticesIds - , int startVertex - , const QMap> &followers - , const QMap &vertexNumber - , int verticesNumber) -{ - for (const qReal::Id &id : verticesIds) { - mInitialIds.insert(id); - mMapIdToInt[id] = vertexNumber[id]; - mVertices.insert(vertexNumber[id]); - } - - mVerticesNumber = verticesNumber; - mStartVertex = startVertex; - - for (const int v : followers.keys()) { - for (const int u : followers[v]) { - mFollowers[v].push_back(u); - mPredecessors[u].push_back(v); - } - } - - calculatePostOrder(); - calculateDominators(); - createInitialNodesForIds(); - - bool somethingChanged = true; - while (somethingChanged) { - somethingChanged = false; - - int t = 0; - while (t <= mMaxPostOrderTime && (mVertices.size() > 1 || !mFollowers[mStartVertex].isEmpty())) { - int v = mPostOrder.key(t); - - QSet reachUnder; - QSet> edgesToRemove = {}; - QMap verticesRoles; - if (isBlock(v, edgesToRemove, verticesRoles)) { - reduceBlock(edgesToRemove, verticesRoles); - } else if (isSwitch(v, edgesToRemove, verticesRoles)) { - reduceSwitch(edgesToRemove, verticesRoles); - } else if (isIfThenElse(v, edgesToRemove, verticesRoles)) { - reduceIfThenElse(edgesToRemove, verticesRoles); - } else if (isIfThen(v, edgesToRemove, verticesRoles)) { - reduceIfThen(edgesToRemove, verticesRoles); - } else if (isInfiniteLoop(v, edgesToRemove, verticesRoles)) { - reduceInfiniteLoop(edgesToRemove, verticesRoles); - } else if (isWhileLoop(v, edgesToRemove, verticesRoles)) { - reduceWhileLoop(edgesToRemove, verticesRoles); - } else if (isHeadOfCycle(v, reachUnder)) { - int minTime = -1; - for (const int vertex : reachUnder) { - if (minTime == -1 || minTime > mPostOrder[vertex]) { - minTime = mPostOrder[vertex]; - } - } - - QMap> nodesWithExits; - int commonExit = -1; - bool isCycle = isCycleWithBreaks(reachUnder, nodesWithExits, commonExit); - QSet verticesWithExits = nodesWithExits.keys().toSet(); - - if (!isCycle) { - t++; - appendNodesDetectedAsNodeWithExit(verticesWithExits, v); - continue; - } - - if (!nodesWithExits.isEmpty() && checkNodes(verticesWithExits)) { - - for (const int vertexInsideLoop : nodesWithExits.keys()) { - for (const int vertexOutsideLoop : nodesWithExits[vertexInsideLoop]) { - if (minTime > mPostOrder[vertexOutsideLoop]) { - minTime = mPostOrder[vertexOutsideLoop]; - } - } - } - - reduceConditionsWithBreaks(v, nodesWithExits, commonExit); - t = minTime; - somethingChanged = true; - appendNodesDetectedAsNodeWithExit(verticesWithExits, v); - continue; - } - } - - if (!verticesRoles.empty()) { - t -= (verticesRoles.size() - 1); - if (t < 0) { - t = 0; - } - - somethingChanged = true; - } else { - t++; - } - } - } - - if (mVertices.size() == 1) { - return mTrees[mStartVertex]; - } - - return nullptr; -} - -bool Structurizator::isBlock(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) != 1) { - return false; - } - - int u = mFollowers[v].first(); - if (outgoingEdgesNumber(u) <= 1 && incomingEdgesNumber(u) == 1 && u != v && mDominators[u].contains(v)) { - verticesRoles["block1"] = v; - verticesRoles["block2"] = u; - - edgesToRemove.insert(qMakePair(v, u)); - return true; - } - - return false; -} - -bool Structurizator::isIfThenElse(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) != 2) { - return false; - } - - int u1 = mFollowers[v].first(); - int u2 = mFollowers[v].last(); - if (incomingEdgesNumber(u1) != 1 || incomingEdgesNumber(u2) != 1 || mDominators[v].contains(u1) - || mDominators[v].contains(u2)) { - return false; - } - - if ((outgoingEdgesNumber(u1) == 0 && outgoingEdgesNumber(u2) == 0) || - (outgoingEdgesNumber(u1) == 1 && outgoingEdgesNumber(u2) == 1 && - mFollowers[u1].first() == mFollowers[u2].first())) { - - verticesRoles["condition"] = v; - verticesRoles["then"] = u1; - verticesRoles["else"] = u2; - - if (outgoingEdgesNumber(u1) > 0) { - verticesRoles["exit"] = mFollowers[u1].first(); - } - - edgesToRemove += { qMakePair(v, u1), qMakePair(v, u2) }; - return true; - } - - return false; -} - -bool Structurizator::isIfThen(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) != 2) { - return false; - } - - int u1 = mFollowers[v].first(); - int u2 = mFollowers[v].last(); - - int thenNumber = -1; - int elseNumber = -1; - if (checkIfThenHelper(u1, u2)) { - thenNumber = u1; - elseNumber = u2; - } else if (checkIfThenHelper(u2, u1)) { - thenNumber = u2; - elseNumber = u1; - } - - if (thenNumber == -1 || elseNumber == v || mDominators[v].contains(thenNumber)) { - return false; - } - - verticesRoles["condition"] = v; - verticesRoles["then"] = thenNumber; - - if (outgoingEdgesNumber(thenNumber) > 0) { - verticesRoles["exit"] = mFollowers[thenNumber].first(); - } - - edgesToRemove = { qMakePair(v, u1), qMakePair(v, u2) }; - - return true; -} - -bool Structurizator::isSwitch(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) < 3) { - return false; - } - - int exit = -1; - QSet vertices = {}; - QSet> edges = {}; - for (const int u : mFollowers[v]) { - if (incomingEdgesNumber(u) != 1 || outgoingEdgesNumber(u) >= 2) { - if (exit == -1) { - exit = u; - } else if (exit != u) { - return false; - } - } else { - if (outgoingEdgesNumber(u) == 1) { - int m = mFollowers[u].first(); - if (exit == -1) { - exit = m; - } else if (m != exit) { - return false; - } - } - vertices.insert(u); - } - - if (u != exit && mDominators[v].contains(u)) { - return false; - } - - edges.insert(qMakePair(v, u)); - } - - verticesRoles["head"] = v; - edgesToRemove = edges; - - int cnt = 1; - for (int u : vertices) { - verticesRoles[QString::number(cnt)] = u; - cnt++; - } - - verticesRoles["exit"] = exit; - - return true; -} - -bool Structurizator::isInfiniteLoop(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) != 1) { - return false; - } - - int u = mFollowers[v].first(); - if (u != v) { - return false; - } - - verticesRoles["body"] = v; - edgesToRemove.insert(qMakePair(v, v)); - return true; -} - -bool Structurizator::isWhileLoop(int v, QSet> &edgesToRemove, QMap &verticesRoles) -{ - if (outgoingEdgesNumber(v) != 2) { - return false; - } - - int u1 = mFollowers[v].first(); - int u2 = mFollowers[v].last(); - - int bodyNumber = -1; - int exitNumber = -1; - if (checkWhileLoopHelper(v, u1)) { - bodyNumber = u1; - exitNumber = u2; - } else if (checkWhileLoopHelper(v, u2)) { - bodyNumber = u2; - exitNumber = u1; - } - - if (bodyNumber == -1) { - return false; - } - - if (mDominators[v].contains(bodyNumber)) { - return false; - } - - edgesToRemove = { qMakePair(v, bodyNumber), qMakePair(bodyNumber, v) }; - - verticesRoles["head"] = v; - verticesRoles["body"] = bodyNumber; - verticesRoles["exit"] = exitNumber; - - return true; -} - -bool Structurizator::checkIfThenHelper(int thenNumber, int exitNumber) -{ - if (incomingEdgesNumber(thenNumber) == 1 && outgoingEdgesNumber(thenNumber) == 1) { - if (mFollowers[thenNumber].contains(exitNumber)) { - return true; - } - } - - return false; -} - -bool Structurizator::checkWhileLoopHelper(int head, int body) -{ - if (incomingEdgesNumber(body) == 1 && outgoingEdgesNumber(body) == 1) { - int w = mFollowers[body].first(); - if (w == head) { - return true; - } - } - - return false; -} - -bool Structurizator::isCycleWithBreaks(QSet &reachUnder, QMap> &nodesWithExits, int &commonExit) -{ - bool result = findCommonExit(reachUnder, nodesWithExits, commonExit); - if (!result) { - return false; - } - - return checkCommonExitUniqueness(commonExit, nodesWithExits); -} - -bool Structurizator::isHeadOfCycle(int v, QSet &reachUnder) -{ - QQueue queueForReachUnder; - - for (const int u : mPredecessors[v]) { - if (mDominators[u].contains(v)) { - queueForReachUnder.push_back(u); - } - } - - while (!queueForReachUnder.empty()) { - int u = queueForReachUnder.front(); - queueForReachUnder.pop_front(); - reachUnder.insert(u); - for (const int w : mPredecessors[u]) { - if (mDominators[w].contains(v) && !reachUnder.contains(w)) { - queueForReachUnder.push_back(w); - } - } - } - - return !reachUnder.isEmpty(); -} - -bool Structurizator::findCommonExit(QSet &reachUnder, QMap> &nodesWithExits, int &commonExit) -{ - commonExit = -1; - QSet exits; - - for (const int u : reachUnder) { - for (const int w : mFollowers[u]) { - if (!reachUnder.contains(w)) { - if (exits.contains(w) || incomingEdgesNumber(w) > 1) { - if (commonExit != -1 && commonExit != w) { - return false; - } - commonExit = w; - } - - exits.insert(w); - nodesWithExits[u].insert(w); - } - } - } - - if (commonExit != -1) { - return true; - } - - QList regionToFindCommonChild; - for (const int exitNumber : exits) { - if (outgoingEdgesNumber(exitNumber) == 1) { - regionToFindCommonChild.append(exitNumber); - } else if (outgoingEdgesNumber(exitNumber) > 1) { - if (commonExit == -1) { - // we have found post-cycle execution point - commonExit = exitNumber; - } else if (commonExit != exitNumber) { - // each cycle can have at most 1 point to transfer execution - return false; - } - } - } - - if (commonExit != -1) { - return true; - } - - // assume that one exit point is commonChild - if (regionToFindCommonChild.size() == 1) { - commonExit = regionToFindCommonChild.first(); - return true; - } - - for (const int exitNumber : regionToFindCommonChild) { - for (const int postExit : mFollowers[exitNumber]) { - if (commonExit == -1) { - commonExit = postExit; - } else if (commonExit != postExit) { - return false; - } - } - } - - return true; -} - -bool Structurizator::checkCommonExitUniqueness(int commonExit, const QMap> &nodesWithExits) -{ - for (const int vertexFromCycle : nodesWithExits.keys()) { - for (const int exit : nodesWithExits[vertexFromCycle]) { - if (commonExit == exit) { - continue; - } - - if (incomingEdgesNumber(exit) != 1 || outgoingEdgesNumber(exit) >= 2) { - return false; - } - - if (outgoingEdgesNumber(exit) == 1 && commonExit != mFollowers[exit].first()) { - return false; - } - } - } - - return true; -} - -bool Structurizator::checkNodes(const QSet &verticesWithExits) -{ - QSet testSet = mWasPreviouslyDetectedAsNodeWithExit.keys().toSet(); - testSet.intersect(verticesWithExits); - return testSet.isEmpty(); -} - -void Structurizator::reduceBlock(QSet> &edgesToRemove, QMap &verticesRoles) -{ - BlockStructurizatorNode *block = new BlockStructurizatorNode(mTrees[verticesRoles["block1"]] - , mTrees[verticesRoles["block2"]], this); - replace(appendVertex(block), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceIfThenElse(QSet> &edgesToRemove, QMap &verticesRoles) -{ - IntermediateStructurizatorNode *exit = nullptr; - if (verticesRoles.contains("exit")) { - exit = mTrees[verticesRoles["exit"]]; - verticesRoles.remove("exit"); - } - - IfStructurizatorNode *ifNode = new IfStructurizatorNode(mTrees[verticesRoles["condition"]] - , mTrees[verticesRoles["then"]] - , mTrees[verticesRoles["else"]] - , exit - , this); - replace(appendVertex(ifNode), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceIfThen(QSet> &edgesToRemove, QMap &verticesRoles) -{ - IntermediateStructurizatorNode *exit = nullptr; - if (verticesRoles.contains("exit")) { - exit = mTrees[verticesRoles["exit"]]; - verticesRoles.remove("exit"); - } - - IfStructurizatorNode *ifNode = new IfStructurizatorNode(mTrees[verticesRoles["condition"]], - mTrees[verticesRoles["then"]] - , nullptr - , exit - , this); - replace(appendVertex(ifNode), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceSwitch(QSet> &edgesToRemove, QMap &verticesRoles) -{ - int v = verticesRoles["head"]; - int exitNodeNumber = verticesRoles["exit"]; - verticesRoles.remove("exit"); - - QSet otherVerteces = verticesRoles.values().toSet(); - otherVerteces.remove(v); - - QList branches; - for (const int u : mFollowers[v]) { - if (otherVerteces.contains(u)) { - branches.append(mTrees[u]); - } else { - branches.append(new SimpleStructurizatorNode(qReal::Id(), this)); - } - } - - IntermediateStructurizatorNode *exitNode = exitNodeNumber == -1 ? nullptr : mTrees[exitNodeNumber]; - SwitchStructurizatorNode *switchNode = new SwitchStructurizatorNode(mTrees[v], branches, exitNode, this); - - replace(appendVertex(switchNode), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceInfiniteLoop(QSet> &edgesToRemove, QMap &verticesRoles) -{ - SelfLoopStructurizatorNode *loopNode = new SelfLoopStructurizatorNode(mTrees[verticesRoles["body"]], this); - - replace(appendVertex(loopNode), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceWhileLoop(QSet> &edgesToRemove, QMap &verticesRoles) -{ - WhileStructurizatorNode *whileNode = new WhileStructurizatorNode(mTrees[verticesRoles["head"]] - , mTrees[verticesRoles["body"]] - , mTrees[verticesRoles["exit"]] - , this); - - verticesRoles.remove("exit"); - replace(appendVertex(whileNode), edgesToRemove, verticesRoles); -} - -void Structurizator::reduceConditionsWithBreaks(int &v, QMap> &nodesWithExits, int commonExit) -{ - QList exitBranches; - QSet> edgesToRemove; - QSet vertices; - for (const int u : nodesWithExits.keys()) { - exitBranches.clear(); - edgesToRemove.clear(); - vertices = {u}; - - for (const int exit : nodesWithExits[u]) { - qReal::Id id = mTrees[exit]->firstId(); - IntermediateStructurizatorNode *node; - if (exit == commonExit) { - node = new BreakStructurizatorNode(id, this); - } else { - node = new BlockStructurizatorNode(mTrees[exit], new BreakStructurizatorNode(id, this), this); - - vertices.insert(exit); - - if (mFollowers[exit].contains(commonExit)) { - edgesToRemove.insert(qMakePair(exit, commonExit)); - } - } - edgesToRemove.insert(qMakePair(u, exit)); - exitBranches.append(node); - } - - StructurizatorNodeWithBreaks *nodeWithBreaks = new StructurizatorNodeWithBreaks(mTrees[u] - , exitBranches, this); - replace(appendVertex(nodeWithBreaks), edgesToRemove, vertices); - - if (u == v) { - v = mTrees.key(nodeWithBreaks); - } - } - - // adding edge from head to common exit - if (commonExit != -1 && !mFollowers[v].contains(commonExit)) { - mFollowers[v].push_back(commonExit); - mPredecessors[commonExit].push_back(v); - } -} - -void Structurizator::replace(int newNodeNumber, QSet> &edgesToRemove, QSet &vertices) -{ - updateEdges(newNodeNumber, edgesToRemove, vertices); - updatePostOrder(newNodeNumber, vertices); - updateDominators(newNodeNumber, vertices); - updateVertices(newNodeNumber, vertices); - removeNodesPreviouslyDetectedAsNodeWithExit(vertices); -} - -void Structurizator::replace(int newNodeNumber, QSet> &edgesToRemove, - QMap &verticesRoles) -{ - QSet vertices = verticesRoles.values().toSet(); - replace(newNodeNumber, edgesToRemove, vertices); -} - -void Structurizator::updateEdges(int newNodeNumber, QSet> &edgesToRemove, QSet &vertices) -{ - for (const QPair p : edgesToRemove) { - mFollowers[p.first].removeAll(p.second); - mPredecessors[p.second].removeAll(p.first); - } - - const QMap> followers = mFollowers; - for (const int v : mVertices) { - for (const int u : followers[v]) { - - int newV = vertices.contains(v) ? newNodeNumber : v; - int newU = vertices.contains(u) ? newNodeNumber : u; - - if (newU == newNodeNumber || newV == newNodeNumber) { - // removing old information - mFollowers[v].removeAll(u); - mPredecessors[u].removeAll(v); - - // inserting new information - if (!mFollowers[newV].contains(newU)) { - mFollowers[newV].push_back(newU); - mPredecessors[newU].push_back(newV); - } - } - } - } - - for (const int v : vertices) { - mFollowers.remove(v); - mPredecessors.remove(v); - } -} - -void Structurizator::updatePostOrder(int newNodeNumber, QSet &verteces) -{ - int maximum = -1; - for (int v : verteces) { - if (maximum == -1 || maximum < mPostOrder[v]) { - maximum = mPostOrder[v]; - } - } - - mPostOrder[newNodeNumber] = maximum; - - for (int v : verteces) { - mPostOrder.remove(v); - } - - mMaxPostOrderTime = mMaxPostOrderTime - verteces.size() + 1; - - QVector times = mPostOrder.values().toVector(); - std::sort(times.begin(), times.end()); - - for (int i = 0; i <= mMaxPostOrderTime; i++) { - int v = mPostOrder.key(times[i]); - mPostOrder[v] = i; - } -} - -void Structurizator::updateDominators(int newNodeNumber, QSet &vertices) -{ - // others - for (int v : mPostOrder.keys()) { - QSet tempSet = mDominators[v]; - tempSet.intersect(vertices); - if (!tempSet.isEmpty()) { - mDominators[v].subtract(vertices); - mDominators[v].insert(newNodeNumber); - } - } - - // new - QSet doms = mVertices; - for (int v : vertices) { - doms.intersect(mDominators[v]); - } - - doms.subtract(vertices); - doms.insert(newNodeNumber); - - mDominators[newNodeNumber] = doms; - - // old - for (int v : vertices) { - mDominators.remove(v); - } -} - -void Structurizator::updateVertices(int newNodeNumber, QSet &vertices) -{ - mStartVertex = vertices.contains(mStartVertex) ? newNodeNumber : mStartVertex; - mVertices.subtract(vertices); - mVertices.insert(newNodeNumber); -} - -void Structurizator::removeNodesPreviouslyDetectedAsNodeWithExit(QSet &vertices) -{ - for (const int v : vertices) { - mWasPreviouslyDetectedAsNodeWithExit.remove(v); - } -} - -void Structurizator::calculateDominators() -{ - for (const int u : mVertices) { - mDominators[u] = mVertices; - } - - mDominators[mStartVertex] = { mStartVertex }; - - bool somethingChanged = true; - while (somethingChanged) { - somethingChanged = false; - - for (const int v : mVertices) { - if (v == mStartVertex) { - continue; - } - - QSet doms = mVertices; - for (const int u : mPredecessors[v]) { - doms = doms.intersect(mDominators[u]); - } - - doms.insert(v); - - if (doms != mDominators[v]) { - mDominators[v] = doms; - somethingChanged = true; - } - } - } - - -} - -void Structurizator::findStartVertex() -{ - for (const int u : mVertices) { - if (mPredecessors[u].isEmpty()) { - mStartVertex = u; - return; - } - } -} - -void Structurizator::calculatePostOrder() -{ - mPostOrder.clear(); - - QMap used; - for (const int v : mVertices) { - used[v] = false; - } - - int currentTime = 0; - dfs(mStartVertex, currentTime, used); - - mMaxPostOrderTime = currentTime - 1; -} - -void Structurizator::createInitialNodesForIds() -{ - for (const int v : mVertices) { - mTrees[v] = new SimpleStructurizatorNode(mMapIdToInt.key(v), this); - } -} - -void Structurizator::dfs(int v, int ¤tTime, QMap &used) -{ - used[v] = true; - for (const int u : mFollowers[v]) { - if (!used[u]) { - dfs(u, currentTime, used); - } - } - - mPostOrder[v] = currentTime; - currentTime++; -} - -void Structurizator::appendNodesDetectedAsNodeWithExit(QSet &vertices, int cycleHead) -{ - for (const int v : vertices) { - mWasPreviouslyDetectedAsNodeWithExit[v] = cycleHead; - } -} - -int Structurizator::appendVertex(IntermediateStructurizatorNode *node) -{ - mVerticesNumber++; - mTrees[mVerticesNumber] = node; - mVertices.insert(mVerticesNumber); - - return mVerticesNumber; -} - -int Structurizator::outgoingEdgesNumber(int v) const -{ - return mFollowers[v].size(); -} - -int Structurizator::incomingEdgesNumber(int v) const -{ - return mPredecessors[v].size(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizator.h b/plugins/robots/generators/generatorBase/src/structurizator.h deleted file mode 100644 index 08e9442403..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizator.h +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include -#include - -#include - -namespace generatorBase { - -class IntermediateStructurizatorNode; -class SimpleStructurizatorNode; -class BreakStructurizatorNode; -class IfStructurizatorNode; -class SwitchStructurizatorNode; -class BlockStructurizatorNode; -class WhileStructurizatorNode; -class SelfLoopStructurizatorNode; -class StructurizatorNodeWithBreaks; - -/// @class Structurizator is aimed to produce control flow AST from diagram performing Structural Analysis. -/// AST Nodes are concrete classes (BlockNode, WhileNode, etc.) of abstract @class IntermediateNode -/// and represent some type of control structure of high-order programming language. -/// -/// We should fill needed structures before performing main algorithm: -/// 1) calculate dominators used for detecting vertices in cycle body; -/// 2) calculate postorder vertices numbers to perform structurizaion from down to up. -/// -/// Structurization is a process of graph transformations made iteratively. -/// Each transformation has four steps: -/// 1) pattern matching, remembering vertices and their roles -/// 2) creating new vertex and IntermediateNode of corresponding subclass -/// 3) reducing graph substituting "old" edges incident to old vertices with "new" ones; -/// 4) updating dominance relationship and postorder -/// -/// These four steps are performed until there would be one vertex with no edges. -/// -/// @return a pointer to an obtained tree and nullptr if structurization was unsuccessfull. -class Structurizator : public QObject -{ - Q_OBJECT - -public: - explicit Structurizator(QObject *parent = nullptr); - - /// main function that performs structurization - IntermediateStructurizatorNode *performStructurization(const QSet &verticesIds, int startVertex - , const QMap> &followers, const QMap &vertexNumber, int verticesNumber); - -private: - typedef int Time; - typedef int VertexNumber; - - /// methods to identify patterns for structural analysis - /// @arg edgesToRemove -- passed by reference. - /// @arg verticesRoles -- passed by reference. - bool isBlock(int v, QSet> &edgesToRemove, QMap &verticesRoles); - bool isIfThenElse(int v, QSet> &edgesToRemove, QMap &verticesRoles); - bool isIfThen(int v, QSet> &edgesToRemove, QMap &verticesRoles); - bool isSwitch(int v, QSet> &edgesToRemove, QMap &verticesRoles); - bool isInfiniteLoop(int v, QSet> &edgesToRemove, QMap &verticesRoles); - bool isWhileLoop(int v, QSet> &edgesToRemove, QMap &verticesRoles); - - /// helper functions for clarifying vertices roles - bool checkIfThenHelper(int thenNumber, int elseNumber); - bool checkWhileLoopHelper(int head, int body); - - /// functions for identifying loops that have "obstructive" vertices with edges going outside loop to EXIT. - /// EXIT --- is a vertex to which control is transfered after loop execution. - /// the main idea is to remove such vertices and edges substituting them with new vertices - /// of class NodeWithBreaks which remember actions to perform before Break. - bool isCycleWithBreaks(QSet &reachUnder, QMap> &nodesWithExits, int &commonExit); - bool isHeadOfCycle(int v, QSet &reachUnder); - bool findCommonExit(QSet &reachUnder, QMap> &nodesWithExits, int &commonExit); - - /// EXIT must be unique. - bool checkCommonExitUniqueness(int commonExit, const QMap> &nodesWithExits); - - /// Vertices with exits must belong only to one loop. - /// This limitation was introduced in order to forbid situation of nested loops when break - /// nodes belong to inner one, because in general such a situation is resolved with - /// introducing new flag-variables. - bool checkNodes(const QSet &verticesWithExits); - - /// methods for reducing recognised pattern - void reduceBlock(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceIfThenElse(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceIfThen(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceSwitch(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceInfiniteLoop(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceWhileLoop(QSet> &edgesToRemove, QMap &verticesRoles); - void reduceConditionsWithBreaks(int &v, QMap> &nodesWithExits, int commonExit); - - /// Replacing some verteces with a new one and proper maintenance of edges - void replace(int newNodeNumber, QSet> &edgesToRemove, QSet &vertices); - void replace(int newNodeNumber, QSet> &edgesToRemove, QMap &verticesRoles); - void updateEdges(int newNodeNumber, QSet> &edgesToRemove, QSet &vertices); - void updatePostOrder(int newNodeNumber, QSet &vertices); - void updateDominators(int newNodeNumber, QSet &vertices); - void updateVertices(int newNodeNumber, QSet &vertices); - - /// methods used before structurization process - void calculateDominators(); - void findStartVertex(); - void calculatePostOrder(); - void createInitialNodesForIds(); - void dfs(int v, int ¤tTime, QMap &used); - - void appendNodesDetectedAsNodeWithExit(QSet &vertices, int cycleHead); - void removeNodesPreviouslyDetectedAsNodeWithExit(QSet &vertices); - int appendVertex(IntermediateStructurizatorNode *node); - - int outgoingEdgesNumber(int v) const; - int incomingEdgesNumber(int v) const; - - QMap mMapIdToInt; - QSet mVertices; - QMap> mFollowers; - QMap> mPredecessors; - QMap> mDominators; - QMap mPostOrder; - QMap mWasPreviouslyDetectedAsNodeWithExit; - - QMap mTrees; - - QSet mInitialIds; - int mVerticesNumber; - int mStartVertex; - int mMaxPostOrderTime; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.cpp deleted file mode 100644 index 68e6ad29f9..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "blockStructurizatorNode.h" - -using namespace generatorBase; - -BlockStructurizatorNode::BlockStructurizatorNode(IntermediateStructurizatorNode *firstNode - , IntermediateStructurizatorNode *secondNode - , QObject *parent) - : IntermediateStructurizatorNode(parent) - , mFirstNode(firstNode) - , mSecondNode(secondNode) -{ -} - -IntermediateStructurizatorNode *BlockStructurizatorNode::firstNode() const -{ - return mFirstNode; -} - -IntermediateStructurizatorNode *BlockStructurizatorNode::secondNode() const -{ - return mSecondNode; -} - -bool BlockStructurizatorNode::analyzeBreak() -{ - if (mBreakWasAnalyzed) { - return mHasBreakInside; - } - - mHasBreakInside = mFirstNode->analyzeBreak() || mSecondNode->analyzeBreak(); - mBreakWasAnalyzed = true; - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type BlockStructurizatorNode::type() const -{ - return Type::block; -} - -qReal::Id BlockStructurizatorNode::firstId() const -{ - return firstNode()->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.h deleted file mode 100644 index 00486706f0..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/blockStructurizatorNode.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include "intermediateStructurizatorNode.h" - -namespace generatorBase { - -class BlockStructurizatorNode : public IntermediateStructurizatorNode -{ - Q_OBJECT - -public: - explicit BlockStructurizatorNode(IntermediateStructurizatorNode *firstNode - , IntermediateStructurizatorNode *secondNode - , QObject *parent); - - IntermediateStructurizatorNode *firstNode() const; - IntermediateStructurizatorNode *secondNode() const; - - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mFirstNode; - IntermediateStructurizatorNode *mSecondNode; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.cpp deleted file mode 100644 index 1a4f896aa2..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "breakStructurizatorNode.h" - -using namespace generatorBase; - -BreakStructurizatorNode::BreakStructurizatorNode(const qReal::Id &id, QObject *parent) - : IntermediateStructurizatorNode(parent) - , mId(id) -{ -} - -IntermediateStructurizatorNode::Type BreakStructurizatorNode::type() const -{ - return breakNode; -} - -qReal::Id BreakStructurizatorNode::firstId() const -{ - return mId; -} - -bool BreakStructurizatorNode::analyzeBreak() -{ - mHasBreakInside = true; - mBreakWasAnalyzed = true; - return mHasBreakInside; -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.cpp deleted file mode 100644 index 5ec2975d42..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "ifStructurizatorNode.h" - -using namespace generatorBase; - -IfStructurizatorNode::IfStructurizatorNode(IntermediateStructurizatorNode *condition - , IntermediateStructurizatorNode *thenBranch - , IntermediateStructurizatorNode *elseBranch - , IntermediateStructurizatorNode *exit - , QObject *parent) - : IntermediateStructurizatorNode(parent) - , mCondition(condition) - , mThenBranch(thenBranch) - , mElseBranch(elseBranch) - , mExit(exit) -{ -} - -IntermediateStructurizatorNode *IfStructurizatorNode::condition() const -{ - return mCondition; -} - -IntermediateStructurizatorNode *IfStructurizatorNode::thenBranch() const -{ - return mThenBranch; -} - -IntermediateStructurizatorNode *IfStructurizatorNode::elseBranch() const -{ - return mElseBranch; -} - -IntermediateStructurizatorNode *IfStructurizatorNode::exit() const -{ - return mExit; -} - -bool IfStructurizatorNode::analyzeBreak() -{ - mHasBreakInside = mThenBranch->analyzeBreak(); - if (mElseBranch) { - mHasBreakInside |= mElseBranch->analyzeBreak(); - } - - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type IfStructurizatorNode::type() const -{ - return Type::ifThenElseCondition; -} - -qReal::Id IfStructurizatorNode::firstId() const -{ - return mCondition->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.h deleted file mode 100644 index 0443e401bc..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/ifStructurizatorNode.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include "intermediateStructurizatorNode.h" - -namespace generatorBase { - -class IfStructurizatorNode : public IntermediateStructurizatorNode -{ - Q_OBJECT - -public: - explicit IfStructurizatorNode(IntermediateStructurizatorNode *condition - , IntermediateStructurizatorNode *thenBranch - , IntermediateStructurizatorNode *elseBranch - , IntermediateStructurizatorNode *exit - , QObject *parent); - - IntermediateStructurizatorNode *condition() const; - IntermediateStructurizatorNode *thenBranch() const; - IntermediateStructurizatorNode *elseBranch() const; - IntermediateStructurizatorNode *exit() const; - - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mCondition; - IntermediateStructurizatorNode *mThenBranch; - IntermediateStructurizatorNode *mElseBranch; - IntermediateStructurizatorNode *mExit; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.h deleted file mode 100644 index 49b0cd68fa..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/intermediateStructurizatorNode.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include - -namespace generatorBase { - -class IntermediateStructurizatorNode : public QObject -{ - Q_OBJECT - -public: - - enum Type { - simple - , block - , ifThenElseCondition - , switchCondition - , infiniteloop - , whileloop - , breakNode - , nodeWithBreaks - }; - - explicit IntermediateStructurizatorNode(QObject *parent); - virtual ~IntermediateStructurizatorNode(); - - virtual Type type() const = 0; - virtual qReal::Id firstId() const = 0; - virtual bool analyzeBreak() = 0; - bool hasBreakInside() const; - -protected: - bool mHasBreakInside; - bool mBreakWasAnalyzed; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.cpp deleted file mode 100644 index b69952be83..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/selfLoopStructurizatorNode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "selfLoopStructurizatorNode.h" - -using namespace generatorBase; - -SelfLoopStructurizatorNode::SelfLoopStructurizatorNode(IntermediateStructurizatorNode *bodyNode, QObject *parent) - : IntermediateStructurizatorNode(parent) - , mBodyNode(bodyNode) -{ -} - -IntermediateStructurizatorNode *SelfLoopStructurizatorNode::bodyNode() const -{ - return mBodyNode; -} - -bool SelfLoopStructurizatorNode::analyzeBreak() -{ - if (mBreakWasAnalyzed) { - return mHasBreakInside; - } - - mHasBreakInside = mBodyNode->analyzeBreak(); - mBreakWasAnalyzed = true; - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type SelfLoopStructurizatorNode::type() const -{ - return Type::infiniteloop; -} - -qReal::Id SelfLoopStructurizatorNode::firstId() const -{ - return mBodyNode->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.cpp deleted file mode 100644 index fd8cac420b..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "structurizatorNodeWithBreaks.h" - -using namespace generatorBase; - -StructurizatorNodeWithBreaks::StructurizatorNodeWithBreaks(IntermediateStructurizatorNode *condition - , const QList &exitBranches - , QObject *parent) - : IntermediateStructurizatorNode(parent) - , mCondition(condition) - , mExitBranches(exitBranches) -{ -} - -IntermediateStructurizatorNode *StructurizatorNodeWithBreaks::condition() const -{ - return mCondition; -} - -QList StructurizatorNodeWithBreaks::exitBranches() const -{ - return mExitBranches; -} - -QList StructurizatorNodeWithBreaks::restBranches() const -{ - return mRestBranches; -} - -void StructurizatorNodeWithBreaks::setRestBranches(const QList &restBranches) -{ - mRestBranches = restBranches; -} - -bool StructurizatorNodeWithBreaks::analyzeBreak() -{ - mHasBreakInside = true; - mBreakWasAnalyzed = true; - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type StructurizatorNodeWithBreaks::type() const -{ - return nodeWithBreaks; -} - -qReal::Id StructurizatorNodeWithBreaks::firstId() const -{ - return mCondition->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.h deleted file mode 100644 index a82c4ca140..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/structurizatorNodeWithBreaks.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include "intermediateStructurizatorNode.h" - -namespace generatorBase { - -class StructurizatorNodeWithBreaks : public IntermediateStructurizatorNode -{ - Q_OBJECT - -public: - explicit StructurizatorNodeWithBreaks(IntermediateStructurizatorNode *condition - , const QList &exitBranches - , QObject *parent); - - IntermediateStructurizatorNode *condition() const; - QList exitBranches() const; - QList restBranches() const; - - void setRestBranches(const QList &restBranches); - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mCondition; - QList mExitBranches; - QList mRestBranches; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.cpp deleted file mode 100644 index 8357361eca..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "switchStructurizatorNode.h" - -using namespace generatorBase; - -SwitchStructurizatorNode::SwitchStructurizatorNode(IntermediateStructurizatorNode *condition - , const QList &branches - , IntermediateStructurizatorNode *exit - , QObject *parent) - : IntermediateStructurizatorNode(parent) - , mCondition(condition) - , mBranches(QList(branches)) - , mExit(exit) -{ -} - -IntermediateStructurizatorNode *SwitchStructurizatorNode::condition() const -{ - return mCondition; -} - -QList SwitchStructurizatorNode::branches() const -{ - return mBranches; -} - -IntermediateStructurizatorNode *SwitchStructurizatorNode::exit() const -{ - return mExit; -} - -bool SwitchStructurizatorNode::analyzeBreak() -{ - if (mBreakWasAnalyzed) { - return mHasBreakInside; - } - - mHasBreakInside = false; - for (IntermediateStructurizatorNode *node : mBranches) { - mHasBreakInside |= node->analyzeBreak(); - } - - mBreakWasAnalyzed = true; - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type SwitchStructurizatorNode::type() const -{ - return Type::switchCondition; -} - -qReal::Id SwitchStructurizatorNode::firstId() const -{ - return mCondition->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.h deleted file mode 100644 index e166c58625..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/switchStructurizatorNode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include "intermediateStructurizatorNode.h" - -namespace generatorBase { - -class SwitchStructurizatorNode : public IntermediateStructurizatorNode -{ - Q_OBJECT - -public: - explicit SwitchStructurizatorNode(IntermediateStructurizatorNode *condition - , const QList &branches - , IntermediateStructurizatorNode *exit - , QObject *parent); - - IntermediateStructurizatorNode *condition() const; - QList branches() const; - IntermediateStructurizatorNode *exit() const; - - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mCondition; - const QList mBranches; - IntermediateStructurizatorNode *mExit; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.cpp deleted file mode 100644 index cbb7154b8a..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#include "whileStructurizatorNode.h" - -using namespace generatorBase; - -WhileStructurizatorNode::WhileStructurizatorNode(IntermediateStructurizatorNode *headNode - , IntermediateStructurizatorNode *bodyNode - , IntermediateStructurizatorNode *exitNode - , QObject *parent) - : IntermediateStructurizatorNode(parent) - , mHeadNode(headNode) - , mBodyNode(bodyNode) - , mExitNode(exitNode) -{ -} - -IntermediateStructurizatorNode *WhileStructurizatorNode::headNode() const -{ - return mHeadNode; -} - -IntermediateStructurizatorNode *WhileStructurizatorNode::bodyNode() const -{ - return mBodyNode; -} - -IntermediateStructurizatorNode *WhileStructurizatorNode::exitNode() const -{ - return mExitNode; -} - -bool WhileStructurizatorNode::analyzeBreak() -{ - if (mBreakWasAnalyzed) { - return mHasBreakInside; - } - - mHasBreakInside = mHeadNode->analyzeBreak() || mBodyNode->analyzeBreak(); - mBreakWasAnalyzed = true; - return mHasBreakInside; -} - -IntermediateStructurizatorNode::Type WhileStructurizatorNode::type() const -{ - return Type::whileloop; -} - -qReal::Id WhileStructurizatorNode::firstId() const -{ - return mHeadNode->firstId(); -} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.h deleted file mode 100644 index c6721abb11..0000000000 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/whileStructurizatorNode.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2018 Konstantin Batoev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ - -#pragma once - -#include "intermediateStructurizatorNode.h" - -namespace generatorBase { - -class WhileStructurizatorNode : public IntermediateStructurizatorNode -{ - Q_OBJECT - -public: - explicit WhileStructurizatorNode(IntermediateStructurizatorNode *headNode - , IntermediateStructurizatorNode *bodyNode - , IntermediateStructurizatorNode *exitNode - , QObject *parent); - - IntermediateStructurizatorNode *headNode() const; - IntermediateStructurizatorNode *bodyNode() const; - IntermediateStructurizatorNode *exitNode() const; - - bool analyzeBreak(); - Type type() const; - qReal::Id firstId() const; -private: - IntermediateStructurizatorNode *mHeadNode; - IntermediateStructurizatorNode *mBodyNode; - IntermediateStructurizatorNode *mExitNode; -}; - -} diff --git a/plugins/robots/generators/generatorBase/src/structurizer.cpp b/plugins/robots/generators/generatorBase/src/structurizer.cpp new file mode 100644 index 0000000000..f6ca39f5e6 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizer.cpp @@ -0,0 +1,209 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "structurizer.h" + +#include "structurizerNodes/structurizerNode.h" +#include "structurizerNodes/simpleStructurizerNode.h" +#include "structurizerNodes/continuationStructurizerNode.h" +#include "structurizerNodes/sequenceStructurizerNode.h" +#include "structurizerNodes/ifStructurizerNode.h" +#include "structurizerNodes/loopStructurizerNode.h" +#include "structurizerNodes/switchStructurizerNode.h" + +#include + +using namespace generatorBase; + +Structurizer::Structurizer(QObject *parent) + : QObject(parent) +{ +} + +StructurizerNode *Structurizer::performStructurization(const QSet &verticesIds + , qReal::Id startVertex + , const QMap> &followers) +{ + mStartVertex = startVertex; + + for (const Vertex &v : verticesIds) { + mVertices.insert(v); + } + + for (const Vertex &v : mVertices) { + for (const Vertex &u : followers[v]) { + mFollowers[v].append(u); + mPredecessors[u].append(v); + } + } + + for (const Vertex &id : mVertices) { + if (mFollowers[id].size() == 0) { + mExits.insert(id); + } + } + + QMap color; + int time = 0; + for (const Vertex &v : verticesIds) { + color[v] = 0; + } + dfs(startVertex, time, color); + + QVector> vertices = {}; + for (const Vertex &v : verticesIds) { + vertices.append(qMakePair(v, mTopologicalOrder[v])); + } + qSort(vertices.begin(), vertices.end(), + [](const QPair &l, const QPair &r) { + return l.second < r.second; + }); + + QVector orderOfResolution; + for (const QPair &e : vertices) { + orderOfResolution.append(e.first); + } + + reorderLoopHeads(orderOfResolution); + + QMap system = {}; + + //system creating + for (const Vertex &id : orderOfResolution) { + SequenceStructurizerNode *var = new SequenceStructurizerNode(this); + if (mFollowers[id].size() <= 1) { + var->addToTheEnd(new SimpleStructurizerNode(id, this)); + if (mFollowers[id].size() == 1) { + var->addToTheEnd(new ContinuationStructurizerNode(mFollowers[id].first(), this)); + } + } else if (mFollowers[id].size() == 2) { + var->addToTheEnd(new IfStructurizerNode(id, mFollowers[id].first(), mFollowers[id].last(), this)); + } else if (mFollowers[id].size() > 2) { + var->addToTheEnd(new SwitchStructurizerNode(id, mFollowers[id], this)); + } + system[id] = var; + } + + //system solving + for (int i = 0; i < orderOfResolution.size(); ++i) { + Vertex v = orderOfResolution[i]; + + //if recursive + if (system[v]->containsContinuation(v)) { + system[v]->derecursivate(v); + } + + //elimination + for (int j = 0; j < orderOfResolution.size(); ++j) { + if (i == j) { + continue; + } + system[orderOfResolution[j]]->mergeConditionalBranches(mExits, mLoopHeads); + + system[orderOfResolution[j]]->factorize(v); + system[orderOfResolution[j]]->replaceContinuation(v, system[v]); + } + } + + return system[mStartVertex]; +} + +void Structurizer::dfs(Vertex v, int ¤tTime, QMap &color) +{ + color[v] = 1; + for (const Vertex &u : mFollowers[v]) { + if (color[u] == 0) { + dfs(u, currentTime, color); + } else if (color[u] == 1) { + mCyclicEdges.append(qMakePair(v, u)); + } + } + mTopologicalOrder[v] = currentTime--; + color[v] = 2; +} + +void Structurizer::reorderLoopHeads(QVector &vertexOrder) +{ + QMap> loopBody = {}; + for (auto &edge : mCyclicEdges) { + QQueue> queue; + queue.enqueue({edge.first, edge.second}); + while (!queue.empty()) { + auto currentPath = queue.dequeue(); + for (auto &nextVertex : mFollowers[currentPath.last()]) { + if (nextVertex == currentPath.first()) { + auto loopHead = currentPath.first(); + for (auto &i : currentPath) { + if (mTopologicalOrder[loopHead] > mTopologicalOrder[i]) { + loopHead = i; + } + } + for (auto &i : currentPath) { + if (i != loopHead) { + loopBody[loopHead].insert(i); + } + } + mLoopHeads.insert(loopHead); + } else if (nextVertex != edge.second && !currentPath.contains(nextVertex)) { + auto newPath = currentPath; + newPath.append(nextVertex); + queue.enqueue(newPath); + } + } + } + } + auto topOrder = vertexOrder; + + for (int i = topOrder.size() - 1; i >= 0; --i) { + Vertex e = topOrder[i]; + bool somethingChanged = true; + while (somethingChanged) { + somethingChanged = false; + for (auto &u : loopBody[e]) { + for (auto &f : mFollowers[u]) { + if (loopBody[e].contains(f) || (f == e)) { + continue; + } + bool isInLoop = true; + for (auto &p : mPredecessors[f]) { + if (!loopBody[e].contains(p) + && !(loopBody.contains(f) && loopBody[f].contains(p))) { + isInLoop = false; + break; + } + } + if (isInLoop) { + somethingChanged = true; + loopBody[e].insert(f); + if (loopBody.contains(f)) { + loopBody[e].unite(loopBody[f]); + } + } + } + } + } + } + + for (int i = topOrder.size() - 1; i >= 0; --i) { + Vertex v = topOrder[i]; + int maxIndex = -1; + for (auto &u : loopBody[v]) { + maxIndex = maxIndex > vertexOrder.lastIndexOf(u) ? maxIndex : vertexOrder.lastIndexOf(u); + } + if (maxIndex > vertexOrder.lastIndexOf(v)) { + vertexOrder.insert(maxIndex + 1, v); + vertexOrder.erase(vertexOrder.begin() + vertexOrder.indexOf(v)); + } + } +} diff --git a/plugins/robots/generators/generatorBase/src/structurizer.h b/plugins/robots/generators/generatorBase/src/structurizer.h new file mode 100644 index 0000000000..550a70f57e --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizer.h @@ -0,0 +1,56 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include +#include + +#include + +namespace generatorBase { + +class StructurizerNode; +class SimpleStructurizerNode; +class ContinuationStructurizerNode; +class IfStructurizerNode; +class LoopStructurizerNode; + +class Structurizer : public QObject +{ +public: + explicit Structurizer(QObject *parent = nullptr); + + /// main function that performs structurization + StructurizerNode *performStructurization(const QSet &verticesIds, qReal::Id startVertex + , const QMap> &followers); + +private: + typedef qReal::Id Vertex; + + void dfs(Vertex v, int ¤tTime, QMap &color); + + QSet mVertices; + QMap> mFollowers; + QMap> mPredecessors; + QMap mTopologicalOrder; + QSet mExits; + QSet mLoopHeads; + + Vertex mStartVertex; + QVector> mCyclicEdges; + + void reorderLoopHeads(QVector &v); +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.cpp similarity index 53% rename from plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.cpp rename to plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.cpp index 21de08ca06..6bd3c368b7 100644 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/simpleStructurizatorNode.cpp +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.cpp @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,33 +12,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "simpleStructurizatorNode.h" +#include "breakStructurizerNode.h" using namespace generatorBase; -SimpleStructurizatorNode::SimpleStructurizatorNode(const qReal::Id &id, QObject *parent) - : IntermediateStructurizatorNode(parent) - , mId(id) +BreakStructurizerNode::BreakStructurizerNode(QObject *parent) + : SimpleStructurizerNode(qReal::Id(), parent) { } -IntermediateStructurizatorNode::Type SimpleStructurizatorNode::type() const +StructurizerNode::Type BreakStructurizerNode::type() const { - return Type::simple; + return breakFromLoop; } -qReal::Id SimpleStructurizatorNode::firstId() const +bool BreakStructurizerNode::isEqual(StructurizerNode * other) const { - return mId; + return other->type() == breakFromLoop; } -bool SimpleStructurizatorNode::analyzeBreak() +StructurizerNode *BreakStructurizerNode::clone() const { - mHasBreakInside = false; - return mHasBreakInside; + return new BreakStructurizerNode(parent()); } -qReal::Id SimpleStructurizatorNode::id() const +bool BreakStructurizerNode::hasBreakOnUpperLevel() const { - return mId; + return true; } diff --git a/plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.h similarity index 66% rename from plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.h rename to plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.h index 734ba56899..2864f9710c 100644 --- a/plugins/robots/generators/generatorBase/src/structurizatorNodes/breakStructurizatorNode.h +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/breakStructurizerNode.h @@ -1,4 +1,4 @@ -/* Copyright 2018 Konstantin Batoev +/* Copyright 2013-2021 CyberTech Labs Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,19 @@ #pragma once -#include "intermediateStructurizatorNode.h" +#include "simpleStructurizerNode.h" namespace generatorBase { -class BreakStructurizatorNode : public IntermediateStructurizatorNode +class BreakStructurizerNode : public SimpleStructurizerNode { - Q_OBJECT - public: - explicit BreakStructurizatorNode(const qReal::Id &id, QObject *parent); + explicit BreakStructurizerNode(QObject *parent = nullptr); Type type() const; - qReal::Id firstId() const; - bool analyzeBreak(); + bool isEqual(StructurizerNode *other) const; + bool hasBreakOnUpperLevel() const; -private: - const qReal::Id mId; + StructurizerNode *clone() const; }; - } diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.cpp new file mode 100644 index 0000000000..bee9e138c9 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.cpp @@ -0,0 +1,117 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "continuationStructurizerNode.h" + +using namespace generatorBase; + +ContinuationStructurizerNode::ContinuationStructurizerNode(const Vertex &id, QObject *parent) + : StructurizerNode(parent) + , mId(id) +{ +} + +StructurizerNode::Type ContinuationStructurizerNode::type() const +{ + return Type::continuation; +} + +bool ContinuationStructurizerNode::containsContinuation(const Vertex &id) const +{ + if (id == Vertex()) { + return true; + } + return id == mId; +} + +int ContinuationStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + if (id == Vertex()) { + return 1; + } + return id == mId ? 1 : 0; +} + +StructurizerNode *ContinuationStructurizerNode::clone() const +{ + return new ContinuationStructurizerNode(mId, parent()); +} + +StructurizerNode::Vertex ContinuationStructurizerNode::id() const +{ + return mId; +} + +bool ContinuationStructurizerNode::isEqual(StructurizerNode * other) const +{ + if (other->type() != continuation) { + return false; + } + return mId == other->id(); +} + +void ContinuationStructurizerNode::dropContinuations(const Vertex &id) +{ + Q_UNUSED(id) +} + +void ContinuationStructurizerNode::factorize(const Vertex &id, bool force) +{ + Q_UNUSED(id) + Q_UNUSED(force) +} + +void ContinuationStructurizerNode::derecursivate(const Vertex &id) +{ + Q_UNUSED(id) +} + +bool ContinuationStructurizerNode::mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) +{ + Q_UNUSED(exits) + Q_UNUSED(loopHeads) + return false; +} + +void ContinuationStructurizerNode::transformDoWhile() +{ +} + +void ContinuationStructurizerNode::dropEmptyConditionals() +{ +} + +StructurizerNode::ConditionTree *ContinuationStructurizerNode::findAllContinuations(const Vertex &id) const +{ + Q_UNUSED(id) + return nullptr; +} + +void ContinuationStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + Q_UNUSED(id) + Q_UNUSED(value) +} + + +int ContinuationStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + Q_UNUSED(id) + return 0; +} + +bool ContinuationStructurizerNode::hasBreakOnUpperLevel() const +{ + return false; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.h new file mode 100644 index 0000000000..1e2814347a --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/continuationStructurizerNode.h @@ -0,0 +1,53 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class ContinuationStructurizerNode : public StructurizerNode +{ +public: + explicit ContinuationStructurizerNode(const Vertex &id, QObject *parent); + + Type type() const; + Vertex id() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + void dropEmptyConditionals(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + bool hasBreakOnUpperLevel() const; + +protected: + const Vertex mId; +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.cpp new file mode 100644 index 0000000000..a719c54017 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.cpp @@ -0,0 +1,211 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "ifStructurizerNode.h" + +#include "continuationStructurizerNode.h" +#include "sequenceStructurizerNode.h" + +using namespace generatorBase; + +StructurizerNode::Type IfStructurizerNode::type() const +{ + return ifThenElse; +} + +bool IfStructurizerNode::isEmpty() const +{ + return (static_cast(mThenBranch)->children().size() == 0) + && (static_cast(mElseBranch)->children().size() == 0); +} + +bool IfStructurizerNode::containsContinuation(const Vertex &id) const +{ + return mThenBranch->containsContinuation(id) || mElseBranch->containsContinuation(id); +} + +int IfStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + return mThenBranch->numberOfContinuation(id) + mElseBranch->numberOfContinuation(id); +} + +IfStructurizerNode::IfStructurizerNode(const Vertex &id, const Vertex &firstId + , const Vertex &secondId, QObject *parent) + : StructurizerNode(parent) +{ + mThenBranch = new SequenceStructurizerNode(parent); + static_cast(mThenBranch) + ->addToTheEnd(new ContinuationStructurizerNode(firstId, parent)); + + mElseBranch = new SequenceStructurizerNode(parent); + static_cast(mElseBranch) + ->addToTheEnd(new ContinuationStructurizerNode(secondId, parent)); + + mCondition = new ConditionTree({id, firstId}); +} + +IfStructurizerNode::IfStructurizerNode(const ConditionTree * ifCondition, QObject *parent) + : StructurizerNode(parent) + , mCondition(ifCondition) + , mThenBranch(new SequenceStructurizerNode(parent)) + , mElseBranch(new SequenceStructurizerNode(parent)) +{ +} + +StructurizerNode *IfStructurizerNode::clone() const +{ + IfStructurizerNode *newIf = new IfStructurizerNode(mCondition->clone(), parent()); + for (auto &e : static_cast(mThenBranch)->children()) { + static_cast(newIf->mThenBranch)->addToTheEnd(e->clone()); + } + for (auto &e : static_cast(mElseBranch)->children()) { + static_cast(newIf->mElseBranch)->addToTheEnd(e->clone()); + } + return newIf; +} + +StructurizerNode::Vertex IfStructurizerNode::id() const +{ + return mCondition->isValue() ? mCondition->value().first : Vertex(); +} + + +StructurizerNode *IfStructurizerNode::thenBranch() +{ + return mThenBranch; +} + +StructurizerNode *IfStructurizerNode::elseBranch() +{ + return mElseBranch; +} + +void IfStructurizerNode::dropContinuations(const Vertex &id) +{ + mThenBranch->dropContinuations(id); + mElseBranch->dropContinuations(id); +} + +bool IfStructurizerNode::isEqual(StructurizerNode *other) const +{ + if (other->type() != ifThenElse) { + return false; + } + if (!mCondition->isEqual(static_cast(other)->mCondition)) { + return false; + } + if (!mThenBranch->isEqual(static_cast(other)->mThenBranch)) { + return false; + } + if (!mElseBranch->isEqual(static_cast(other)->mElseBranch)) { + return false; + } + return true; +} + +StructurizerNode::ConditionTree *IfStructurizerNode::findAllContinuations(const Vertex &id) const +{ + ConditionTree *tree = nullptr; + if (mThenBranch->containsContinuation(id)) { + ConditionTree *thenTree = mThenBranch->findAllContinuations(id); + if (thenTree == nullptr) { + tree = mCondition->clone(); + } else { + tree = new ConditionTree(ConditionTree::AND, mCondition->clone(), thenTree); + } + } + + if (mElseBranch->containsContinuation(id)) { + ConditionTree *invertedCondition = mCondition->clone(); + invertedCondition->invert(); + ConditionTree *elseTree = mElseBranch->findAllContinuations(id); + if (elseTree == nullptr) { + elseTree = invertedCondition; + } else { + elseTree = new ConditionTree(ConditionTree::AND, invertedCondition, elseTree); + } + if (tree == nullptr) { + tree = elseTree; + } else { + tree = new ConditionTree(ConditionTree::OR, tree, elseTree); + } + } + + if (tree == nullptr || tree->isTrue()) { + delete tree; + return nullptr; + } + return tree; +} + +void IfStructurizerNode::factorize(const Vertex &id, bool force) +{ + mThenBranch->factorize(id, force); + mElseBranch->factorize(id, force); +} + +void IfStructurizerNode::derecursivate(const Vertex &id) +{ + Q_UNUSED(id) +} + +bool IfStructurizerNode::mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) +{ + if (mThenBranch->mergeConditionalBranches(exits, loopHeads)) + return true; + if (mElseBranch->mergeConditionalBranches(exits, loopHeads)) + return true; + return false; +} + +void IfStructurizerNode::transformDoWhile() +{ + mThenBranch->transformDoWhile(); + mElseBranch->transformDoWhile(); +} + +void IfStructurizerNode::dropEmptyConditionals() +{ + mThenBranch->dropEmptyConditionals(); + mElseBranch->dropEmptyConditionals(); +} + +StructurizerNode::ConditionTree *IfStructurizerNode::condition() const +{ + return mCondition->clone(); +} + +IfStructurizerNode::~IfStructurizerNode() +{ + delete mCondition; +} + +void IfStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + mThenBranch->replaceContinuation(id, value); + mElseBranch->replaceContinuation(id, value); +} + +int IfStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + int count = mCondition->numberOfFirstVertex(id); + count += mThenBranch->numberOfConditionCalculating(id); + count += mElseBranch->numberOfConditionCalculating(id); + return count; +} + +bool IfStructurizerNode::hasBreakOnUpperLevel() const +{ + return mThenBranch->hasBreakOnUpperLevel() || mElseBranch->hasBreakOnUpperLevel(); +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.h new file mode 100644 index 0000000000..2717eec41e --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/ifStructurizerNode.h @@ -0,0 +1,62 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class IfStructurizerNode : public StructurizerNode +{ +public: + explicit IfStructurizerNode(const Vertex &id, const Vertex &firstId, const Vertex &secondId, QObject *parent); + explicit IfStructurizerNode(const ConditionTree *ifCondition, QObject *parent); + + Type type() const; + Vertex id() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + bool hasBreakOnUpperLevel() const; + + void dropEmptyConditionals(); + + ConditionTree *condition() const; + StructurizerNode *thenBranch(); + StructurizerNode *elseBranch(); + bool isEmpty() const; + ~IfStructurizerNode(); + +protected: + const ConditionTree *mCondition; + StructurizerNode *mThenBranch; + StructurizerNode *mElseBranch; +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.cpp new file mode 100644 index 0000000000..adf786eaea --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.cpp @@ -0,0 +1,153 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "loopStructurizerNode.h" + +#include "sequenceStructurizerNode.h" + +using namespace generatorBase; + +StructurizerNode::Type LoopStructurizerNode::type() const +{ + return Type::loop; +} + +bool LoopStructurizerNode::containsContinuation(const Vertex &id) const +{ + return mBody->containsContinuation(id); +} + +int LoopStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + return mBody->numberOfContinuation(id); +} + +LoopStructurizerNode::LoopStructurizerNode(QObject *parent) + : StructurizerNode(parent) + , mId(Vertex()) + , mInvertedCondition(false) + , mBody(new SequenceStructurizerNode(parent)) +{ +} + +LoopStructurizerNode::LoopStructurizerNode(const Vertex &id, bool invertCondition, QObject *parent) + : StructurizerNode(parent) + , mId(id) + , mInvertedCondition(invertCondition) + , mBody(new SequenceStructurizerNode(parent)) +{ +} + +StructurizerNode *LoopStructurizerNode::clone() const +{ + LoopStructurizerNode *loop = nullptr; + if (!mId.isNull()) { + loop = new LoopStructurizerNode(mId, mInvertedCondition, parent()); + } else { + loop = new LoopStructurizerNode(parent()); + } + for (StructurizerNode *&e : static_cast(mBody)->children()) { + loop->addToBody(e->clone()); + } + return loop; +} + +StructurizerNode::Vertex LoopStructurizerNode::id() const +{ + return mId; +} + +bool LoopStructurizerNode::isEqual(StructurizerNode *other) const +{ + if (other->type() != loop) { + return false; + } + if (mId != other->id()) { + return false; + } + if (mInvertedCondition != static_cast(other)->mInvertedCondition) { + return false; + } + if (!mBody->isEqual(static_cast(other)->mBody)) { + return false; + } + return true; +} + +void LoopStructurizerNode::dropContinuations(const Vertex &id) +{ + mBody->dropContinuations(id); +} + +void LoopStructurizerNode::factorize(const Vertex &id, bool force) +{ + Q_UNUSED(id) + Q_UNUSED(force) +} + +void LoopStructurizerNode::derecursivate(const Vertex &id) +{ + Q_UNUSED(id) +} + +bool LoopStructurizerNode::mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) +{ + return mBody->mergeConditionalBranches(exits, loopHeads); +} + +void LoopStructurizerNode::transformDoWhile() +{ + mBody->transformDoWhile(); +} + +void LoopStructurizerNode::dropEmptyConditionals() +{ + mBody->dropEmptyConditionals(); +} + +StructurizerNode::ConditionTree *LoopStructurizerNode::findAllContinuations(const Vertex &id) const +{ + Q_UNUSED(id); + return nullptr; +} + +StructurizerNode *LoopStructurizerNode::body() +{ + return mBody; +} + +void LoopStructurizerNode::addToBody(StructurizerNode *e) +{ + static_cast(mBody)->addToTheEnd(e); +} + +void LoopStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + mBody->replaceContinuation(id, value); +} + +int LoopStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + return (mId == id ? 1 : 0) + mBody->numberOfConditionCalculating(id); +} + +bool LoopStructurizerNode::isInverted() const +{ + return mInvertedCondition; +} + +bool LoopStructurizerNode::hasBreakOnUpperLevel() const +{ + return false; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.h new file mode 100644 index 0000000000..e24a3e1c0b --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/loopStructurizerNode.h @@ -0,0 +1,60 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class LoopStructurizerNode : public StructurizerNode +{ +public: + explicit LoopStructurizerNode(QObject *parent); + explicit LoopStructurizerNode(const Vertex &id, bool invertCondition, QObject *parent); + + Type type() const; + Vertex id() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + bool hasBreakOnUpperLevel() const; + + void dropEmptyConditionals(); + + bool isInverted() const; + StructurizerNode *body(); + void addToBody(StructurizerNode *e); + +protected: + const Vertex mId; + const bool mInvertedCondition; + StructurizerNode *mBody; +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.cpp new file mode 100644 index 0000000000..6993039faf --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.cpp @@ -0,0 +1,401 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "sequenceStructurizerNode.h" + +#include "continuationStructurizerNode.h" +#include "ifStructurizerNode.h" +#include "loopStructurizerNode.h" +#include "switchStructurizerNode.h" +#include "breakStructurizerNode.h" + +using namespace generatorBase; + +SequenceStructurizerNode::SequenceStructurizerNode(QObject *parent) + : StructurizerNode(parent) + , mChildren({}) +{ +} + +StructurizerNode::Type SequenceStructurizerNode::type() const +{ + return sequence; +} + +StructurizerNode::Vertex SequenceStructurizerNode::id() const +{ + return Vertex(); +} + +bool SequenceStructurizerNode::containsContinuation(const Vertex &id) const +{ + for (auto e : mChildren) { + if (e->containsContinuation(id)) { + return true; + } + } + return false; +} + +void SequenceStructurizerNode::dropContinuations(const Vertex &id) +{ + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->type() == StructurizerNode::continuation) { + if (mChildren[i]->id() == id) { + mChildren.erase(mChildren.begin() + i--); + } + } else { + mChildren[i]->dropContinuations(id); + } + } +} + +int SequenceStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + int count = 0; + for (auto e : mChildren) { + count = count + e->numberOfContinuation(id); + } + return count; +} + + + +void SequenceStructurizerNode::addToTheEnd(StructurizerNode *s) { + if (s->type() == sequence) { + for (StructurizerNode *e : static_cast(s)->mChildren) { + mChildren.append(e); + } + } else { + mChildren.append(s); + } +} + + + +StructurizerNode *SequenceStructurizerNode::clone() const +{ + SequenceStructurizerNode *x = new SequenceStructurizerNode(parent()); + for (auto e : mChildren) { + x->addToTheEnd(e); + } + return x; +} + +QVector SequenceStructurizerNode::children() +{ + return mChildren; +} + + +bool SequenceStructurizerNode::isEqual(StructurizerNode *other) const +{ + if (other->type() != sequence) { + return false; + } + for (int i = 0; i < mChildren.size(); ++i) { + if (!mChildren[i]->isEqual(static_cast(other)->mChildren[i])) { + return false; + } + } + return true; +} + +StructurizerNode::ConditionTree *SequenceStructurizerNode::findAllContinuations(const Vertex &id) const +{ + ConditionTree *finalTree = nullptr; + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->containsContinuation(id)) { + ConditionTree *tree = mChildren[i]->findAllContinuations(id); + if (tree == nullptr) { + delete finalTree; + return nullptr; + } + if (finalTree == nullptr) { + finalTree = tree; + } else { + finalTree = new ConditionTree(ConditionTree::OR, finalTree, tree); + if (finalTree->isTrue()) { + delete finalTree; + return nullptr; + } + } + } + } + return finalTree; +} + +void SequenceStructurizerNode::factorize(const Vertex &id, bool force) +{ + if (numberOfContinuation(id) == 0 + || (!force && (numberOfContinuation(id) == 1))) { + return; + } + ConditionTree *ifCondition = nullptr; + bool always = false; + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->containsContinuation(id)) { + if (mChildren[i]->type() == loop) { + auto loopBody = static_cast(mChildren[i])->body(); + static_cast(loopBody)->addBreaksToLoopFor(id); + ConditionTree *newIf = loopBody->findAllContinuations(id); + loopBody->replaceContinuation(id, new BreakStructurizerNode(parent())); + mChildren.insert(i + 1, new IfStructurizerNode(newIf, parent())); + } else { + mChildren[i]->factorize(id, true); + if (always) { + continue; + } + ConditionTree *newCase = mChildren[i]->findAllContinuations(id); + if (newCase == nullptr) { + always = true; + delete ifCondition; + ifCondition = nullptr; + } else { + if (ifCondition == nullptr) { + ifCondition = newCase; + } else { + ifCondition = new ConditionTree(ConditionTree::OR, newCase, ifCondition); + } + } + } + } + } + + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->containsContinuation(id)) { + if (mChildren[i]->type() == continuation) { + mChildren.erase(mChildren.begin() + i--); + } else { + mChildren[i]->dropContinuations(id); + } + } + } + + if (ifCondition == nullptr || ifCondition->isTrue()) { + delete ifCondition; + mChildren.append(new ContinuationStructurizerNode(id, parent())); + } else { + StructurizerNode *newIf = new IfStructurizerNode(ifCondition, parent()); + StructurizerNode *thenBranch = static_cast(newIf)->thenBranch(); + static_cast(thenBranch) + ->addToTheEnd(new ContinuationStructurizerNode(id, parent())); + mChildren.append(newIf); + } + dropEmptyConditionals(); +} + +void SequenceStructurizerNode::derecursivate(const Vertex &id) +{ + if (mChildren.size() == 1 && mChildren[0]->type() == ifThenElse) { + auto onlyIf = static_cast(mChildren[0]); + auto thenBranch = static_cast(onlyIf->thenBranch()); + auto elseBranch = static_cast(onlyIf->elseBranch()); + if (thenBranch->containsContinuation(id) + && thenBranch->numberOfContinuation(id) == thenBranch->numberOfContinuation() + && !elseBranch->containsContinuation(id)) + { + thenBranch->dropContinuations(id); + auto ifCondition = onlyIf->condition(); + auto loop = new LoopStructurizerNode(ifCondition->value().first + , ifCondition->isInverted(), parent()); + + for (auto &e : thenBranch->mChildren) { + loop->addToBody(e); + } + for (auto &e : elseBranch->mChildren) { + mChildren.append(e); + } + mChildren.pop_front(); + mChildren.prepend(loop); + return; + } + + if (elseBranch->containsContinuation(id) + && elseBranch->numberOfContinuation(id) == elseBranch->numberOfContinuation() + && !thenBranch->containsContinuation(id)) + { + elseBranch->dropContinuations(id); + auto invertedCondition = onlyIf->condition(); + invertedCondition->invert(); + + auto loop = new LoopStructurizerNode(invertedCondition->value().first + , invertedCondition->isInverted(), parent()); + + for (auto &e : elseBranch->mChildren) { + loop->addToBody(e); + } + for (auto &e : thenBranch->mChildren) { + mChildren.append(e); + } + mChildren.pop_front(); + mChildren.prepend(loop); + return; + } + } + + dropContinuations(id); + LoopStructurizerNode *loop = new LoopStructurizerNode(parent()); + for (int i = 0; i <= mChildren.size() - 1; ++i) { + loop->addToBody(mChildren[i]); + } + mChildren.clear(); + mChildren.append(loop); +} + +bool SequenceStructurizerNode::mergeConditionalBranches(const QSet &exits + , const QSet &loopHeads) +{ + bool result = false; + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->mergeConditionalBranches(exits, loopHeads)) { + result = true; + } + if (mChildren[i]->type() == ifThenElse) { + SequenceStructurizerNode *first = static_cast( + static_cast(mChildren[i])->thenBranch()); + SequenceStructurizerNode *second = static_cast( + static_cast(mChildren[i])->elseBranch()); + if (first->mChildren.size() == 0 || second->mChildren.size() == 0) { + continue; + } + if (!loopHeads.contains(mChildren[i]->id())) { + if ((first->mChildren.last()->type() == continuation) + && (second->mChildren.last()->type() == simple) + && exits.contains(second->mChildren.last()->id())) + { + second->addToTheEnd(first->mChildren.last()->clone()); + } else if ((second->mChildren.last()->type() == continuation) + && (first->mChildren.last()->type() == simple) + && exits.contains(first->mChildren.last()->id())) + { + first->addToTheEnd(second->mChildren.last()->clone()); + } + } + if (first->mChildren.last()->type() == continuation + && second->mChildren.last()->type() == continuation + && first->mChildren.last()->id() == second->mChildren.last()->id()) + { + result = true; + mChildren.insert(i + 1, first->mChildren.last()->clone()); + first->mChildren.pop_back(); + second->mChildren.pop_back(); + } + } else if (mChildren[i]->type() == switchCase) { + auto thisSwitch = static_cast(mChildren[i]); + QSet endContinuations; + int nonExitCount = 0; + for (auto &e : thisSwitch->branches()) { + if (static_cast(e)->mChildren.size() > 0 + && static_cast(e) + ->mChildren.last()->type() == continuation) + { + endContinuations.insert(static_cast(e) + ->mChildren.last()->id()); + } + if (static_cast(e)->mChildren.size() > 0 + && static_cast(e)->mChildren.last()->type() == simple + && !exits.contains(static_cast(e)->mChildren.last()->id())) { + nonExitCount += 1; + } + if (static_cast(e)->mChildren.size() == 0) { + nonExitCount += 1; + } + } + if ((endContinuations.size() == 1) && (nonExitCount == 0)) { + result = true; + mChildren.insert(i + 1, new ContinuationStructurizerNode(*endContinuations.begin(), parent())); + thisSwitch->dropContinuations(*endContinuations.begin()); + } + } + } + return result; +} + +void SequenceStructurizerNode::transformDoWhile() +{ +} + +void SequenceStructurizerNode::dropEmptyConditionals() +{ + for (int j = 0; j < mChildren.size(); ++j) { + if (mChildren[j]->type() == ifThenElse && static_cast(mChildren[j])->isEmpty()) { + mChildren.erase(mChildren.begin() + j--); + } else if (mChildren[j]->type() == switchCase + && static_cast(mChildren[j])->isEmpty()) + { + mChildren.erase(mChildren.begin() + j--); + } else { + mChildren[j]->dropEmptyConditionals(); + } + } +} + +void SequenceStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->type() == continuation && mChildren[i]->id() == id) { + mChildren.erase(mChildren.begin() + i--); + if (value->type() == sequence) { + for (StructurizerNode *&e : static_cast(value)->mChildren) { + mChildren.insert(mChildren.begin() + ++i, e->clone()); + } + } else { + mChildren.insert(mChildren.begin() + ++i, value->clone()); + } + } else { + mChildren[i]->replaceContinuation(id, value); + } + } +} + +int SequenceStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + int count = 0; + for (StructurizerNode *e : mChildren) { + count += e->numberOfConditionCalculating(id); + } + return count; +} + +void SequenceStructurizerNode::addBreaksToLoopFor(const Vertex &id) +{ + for (int i = 0; i < mChildren.size(); ++i) { + if (mChildren[i]->type() == ifThenElse) { + auto thisIf = static_cast(mChildren[i]); + static_cast(thisIf->thenBranch())->addBreaksToLoopFor(id); + static_cast(thisIf->elseBranch())->addBreaksToLoopFor(id); + } else if (mChildren[i]->type() == loop) { + auto thisLoop = static_cast(mChildren[i]); + static_cast(thisLoop->body())->addBreaksToLoopFor(id); + ConditionTree *breakCondition = static_cast( + thisLoop->body())->findAllContinuations(id); + thisLoop->replaceContinuation(id, new BreakStructurizerNode(parent())); + auto breakIf = new IfStructurizerNode(breakCondition, parent()); + mChildren.insert(++i, breakIf); + static_cast(breakIf->thenBranch()) + ->addToTheEnd(new ContinuationStructurizerNode(id, parent())); + } + } +} + +bool SequenceStructurizerNode::hasBreakOnUpperLevel() const +{ + for (const auto &e : mChildren) { + if (e->hasBreakOnUpperLevel()) { + return true; + } + } + return false; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.h new file mode 100644 index 0000000000..ee444787e8 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/sequenceStructurizerNode.h @@ -0,0 +1,58 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class SequenceStructurizerNode : public StructurizerNode +{ +public: + explicit SequenceStructurizerNode(QObject *parent); + + Type type() const; + Vertex id() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + bool hasBreakOnUpperLevel() const; + + void dropEmptyConditionals(); + + void addToTheEnd(StructurizerNode *); + QVector children(); + +protected: + QVector mChildren; + + void addBreaksToLoopFor(const Vertex &id); +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.cpp new file mode 100644 index 0000000000..bd0ddb5a31 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.cpp @@ -0,0 +1,113 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "simpleStructurizerNode.h" + +using namespace generatorBase; + +SimpleStructurizerNode::SimpleStructurizerNode(const Vertex &id, QObject *parent) + : StructurizerNode(parent) + , mId(id) +{ +} + +StructurizerNode::Type SimpleStructurizerNode::type() const +{ + return Type::simple; +} + +bool SimpleStructurizerNode::containsContinuation(const Vertex &id) const +{ + Q_UNUSED(id) + return false; +} + +int SimpleStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + Q_UNUSED(id) + return 0; +} + +StructurizerNode *SimpleStructurizerNode::clone() const +{ + return new SimpleStructurizerNode(mId, parent()); +} + +StructurizerNode::Vertex SimpleStructurizerNode::id() const +{ + return mId; +} + +bool SimpleStructurizerNode::isEqual(StructurizerNode * other) const +{ + if (other->type() != simple) { + return false; + } + return mId == other->id(); +} + +void SimpleStructurizerNode::dropContinuations(const Vertex &id) +{ + Q_UNUSED(id) +} + +void SimpleStructurizerNode::factorize(const Vertex &id, bool force) +{ + Q_UNUSED(id) + Q_UNUSED(force) +} + +void SimpleStructurizerNode::derecursivate(const Vertex &id) +{ + Q_UNUSED(id) +} + +bool SimpleStructurizerNode::mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) +{ + Q_UNUSED(exits) + Q_UNUSED(loopHeads) + return false; +} + +void SimpleStructurizerNode::transformDoWhile() +{ +} + +void SimpleStructurizerNode::dropEmptyConditionals() +{ +} + +StructurizerNode::ConditionTree *SimpleStructurizerNode::findAllContinuations(const Vertex &id) const +{ + Q_UNUSED(id) + return nullptr; +} + +void SimpleStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + Q_UNUSED(id) + Q_UNUSED(value) +} + + +int SimpleStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + Q_UNUSED(id) + return 0; +} + +bool SimpleStructurizerNode::hasBreakOnUpperLevel() const +{ + return false; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.h new file mode 100644 index 0000000000..2f5bad1f84 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/simpleStructurizerNode.h @@ -0,0 +1,53 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class SimpleStructurizerNode : public StructurizerNode +{ +public: + explicit SimpleStructurizerNode(const Vertex &id, QObject *parent); + + Vertex id() const; + Type type() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + bool hasBreakOnUpperLevel() const; + + void dropEmptyConditionals(); + +protected: + const Vertex mId; +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.cpp new file mode 100644 index 0000000000..50afa905ba --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.cpp @@ -0,0 +1,198 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "structurizerNode.h" + +using namespace generatorBase; + +StructurizerNode::StructurizerNode(QObject *parent) + : QObject(parent) +{ +} + +StructurizerNode::~StructurizerNode() +{ +} + +StructurizerNode::ConditionTree::ConditionTree(const QPair &idPair) + : mInverted(false), mIsOperator(false),mIsValue(true), mValue(idPair), mLeft(nullptr), mRight(nullptr) +{ +} + +StructurizerNode::ConditionTree::ConditionTree(Operator o, ConditionTree *left, ConditionTree *right) + : mInverted(false), mIsOperator(true), mIsValue(false), mOperator(o), mLeft(left), mRight(right) +{ +} + +void StructurizerNode::ConditionTree::invert() +{ + mInverted = true; +} + +bool StructurizerNode::ConditionTree::isValue() const +{ + return mIsValue; +} + +bool StructurizerNode::ConditionTree::isBoolOperator() const +{ + return mIsOperator; +} + +bool StructurizerNode::ConditionTree::isInverted() const +{ + return mInverted; +} + +bool StructurizerNode::ConditionTree::isEqual(const ConditionTree *x) const +{ + if (x == nullptr) { + return false; + } + if ((mInverted != x->mInverted) || (mIsOperator != x->mIsOperator) || (mIsValue != x->mIsValue)) { + return false; + } + if ((mIsOperator && !(mOperator == x->mOperator)) || (mIsValue && !(mValue == x->mValue))) { + return false; + } + if ((mLeft != nullptr) xor (x->mLeft != nullptr)) + return false; + if ((mLeft != nullptr) && !mLeft->isEqual(x->mLeft)) + return false; + if ((mRight != nullptr) xor (x->mRight != nullptr)) + return false; + if ((mRight != nullptr) && !mRight->isEqual(x->mRight)) + return false; + return true; +} + +bool StructurizerNode::ConditionTree::isNegativeTo(const ConditionTree *x) const +{ + if (x == nullptr) { + return false; + } + if (mInverted == x->mInverted) { + return false; + } + if ((mLeft == nullptr && x->mLeft != nullptr) || (mLeft != nullptr && !mLeft->isEqual(x->mLeft))) { + return false; + } + if ((mRight == nullptr && x->mRight != nullptr) || (mRight != nullptr && !mRight->isEqual(x->mRight))) { + return false; + } + return true; +} + +StructurizerNode::ConditionTree *StructurizerNode::ConditionTree::clone() const +{ + ConditionTree *a = nullptr; + if (mIsOperator) { + a = new ConditionTree(mOperator + , (mLeft != nullptr) ? mLeft->clone() : nullptr + , (mRight != nullptr) ? mRight->clone() : nullptr); + } else { + a = new ConditionTree(mValue); + } + a->mInverted = mInverted; + return a; +} + +QPair StructurizerNode::ConditionTree::value() const +{ + return mValue; +} + +StructurizerNode::ConditionTree::Operator StructurizerNode::ConditionTree::boolOperator() const +{ + return mOperator; +} + +StructurizerNode::ConditionTree *StructurizerNode::ConditionTree::left() +{ + return mLeft; +} + +StructurizerNode::ConditionTree *StructurizerNode::ConditionTree::right() +{ + return mRight; +} + + +StructurizerNode::ConditionTree::~ConditionTree() +{ + delete mLeft; + delete mRight; +} + +int StructurizerNode::ConditionTree::numberOfFirstVertex(const Vertex &id) const +{ + if (mIsValue) { + return (mValue.first == id) ? 1 : 0; + } + if (mIsOperator) { + return mLeft->numberOfFirstVertex(id) + mRight->numberOfFirstVertex(id); + } + return false; +} + +bool StructurizerNode::ConditionTree::isTrue() const +{ + QSet> allValues; + findAllValues(allValues); + QVector> listValues; + QMap, bool> boolMapValues; + for (auto &v : allValues) { + listValues.append(v); + } + QVector binSubset = QVector(listValues.size() + 1, 0); + while (binSubset[0] == 0) { + for (int i = 0; i < listValues.size(); ++i) { + boolMapValues[listValues[i]] = binSubset[i + 1]; + } + if (!calculateValue(boolMapValues)) { + return false; + } + int i = binSubset.size() - 1; + while (binSubset[i] == 1) { + binSubset[i] = 0; + --i; + } + binSubset[i] = 1; + } + return true; +} + +void StructurizerNode::ConditionTree::findAllValues(QSet> &values) const +{ + if (mIsValue) { + values.insert(mValue); + return; + } + mRight->findAllValues(values); + mLeft->findAllValues(values); +} + +bool StructurizerNode::ConditionTree::calculateValue(const QMap, bool> &values) const +{ + if (mIsValue) { + return mInverted ? !values[mValue] : values[mValue]; + } + + bool right = mRight->calculateValue(values); + bool left = mLeft->calculateValue(values); + + bool result = (mOperator == OR) ? (right || left) : (right && left); + + return mInverted ? !result : result; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.h new file mode 100644 index 0000000000..567dfe87c8 --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/structurizerNode.h @@ -0,0 +1,96 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include + +namespace generatorBase { + +class StructurizerNode : public QObject +{ +public: + enum Type { + simple + , continuation + , loop + , ifThenElse + , switchCase + , sequence + , breakFromLoop + }; + + typedef qReal::Id Vertex; + + class ConditionTree { + public: + enum Operator {OR, AND}; + + ConditionTree(const QPair &idPair); + ConditionTree(Operator o, ConditionTree *left, ConditionTree *right); + void invert(); + bool isValue() const; + bool isBoolOperator() const; + bool isInverted() const; + QPair value() const; + Operator boolOperator() const; + ConditionTree *left(); + ConditionTree *right(); + bool isEqual(const ConditionTree *x) const; + bool isNegativeTo(const ConditionTree *x) const; + bool isTrue() const; + ConditionTree *clone() const; + + int numberOfFirstVertex(const Vertex &id) const; + ~ConditionTree(); + + private: + bool calculateValue(const QMap, bool> &values) const; + void findAllValues(QSet> &values) const; + + bool mInverted; + const bool mIsOperator; + const bool mIsValue; + QPair mValue; + Operator mOperator; + ConditionTree *mLeft; + ConditionTree *mRight; + }; + + explicit StructurizerNode(QObject *parent); + ~StructurizerNode(); + + virtual Type type() const = 0; + virtual Vertex id() const = 0; + + virtual bool containsContinuation(const Vertex &id = Vertex()) const = 0; + virtual void dropContinuations(const Vertex &id) = 0; + virtual int numberOfContinuation(const Vertex &id = Vertex()) const = 0; + + virtual void factorize(const Vertex &id, bool force = false) = 0; + virtual void derecursivate(const Vertex &id) = 0; + virtual void replaceContinuation(const Vertex &id, StructurizerNode *value) = 0; + + virtual bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) = 0; + + virtual void transformDoWhile() = 0; + virtual ConditionTree *findAllContinuations(const Vertex &id) const = 0; + virtual bool isEqual(StructurizerNode *other) const = 0; + virtual StructurizerNode *clone() const = 0; + virtual int numberOfConditionCalculating(const Vertex &id) const = 0; + virtual bool hasBreakOnUpperLevel() const = 0; + + virtual void dropEmptyConditionals() = 0; +}; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.cpp b/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.cpp new file mode 100644 index 0000000000..7072a29c7a --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.cpp @@ -0,0 +1,258 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "switchStructurizerNode.h" + +#include "continuationStructurizerNode.h" +#include "sequenceStructurizerNode.h" + +using namespace generatorBase; + +StructurizerNode::Type SwitchStructurizerNode::type() const +{ + return Type::switchCase; +} + +bool SwitchStructurizerNode::isEmpty() const +{ + for (auto *t : mBranches) { + if (static_cast(t)->children().size() > 0) { + return false; + } + } + if (static_cast(mDefaultBranch.second)->children().size() > 0) { + return false; + } + return true; +} + +bool SwitchStructurizerNode::containsContinuation(const Vertex &id) const +{ + for (auto *t : mBranches) { + if (t->containsContinuation(id)) { + return true; + } + } + if (mDefaultBranch.second->containsContinuation(id)) { + return true; + } + return false; +} + +int SwitchStructurizerNode::numberOfContinuation(const Vertex &id) const +{ + int count = 0; + for (auto *t : mBranches) { + count += t->numberOfContinuation(id); + } + count += mDefaultBranch.second->numberOfContinuation(id); + return count; +} + +SwitchStructurizerNode::SwitchStructurizerNode(const Vertex &id, const QVector &branches, QObject *parent) + : StructurizerNode(parent) + , mId(id) +{ + auto defaultBranch = new SequenceStructurizerNode(parent); + defaultBranch->addToTheEnd(new ContinuationStructurizerNode(branches.last(), parent)); + mDefaultBranch = qMakePair(branches.last(), defaultBranch); + for (int i = 0; i < branches.size() - 1; ++i) { + auto branch = new SequenceStructurizerNode(parent); + branch->addToTheEnd(new ContinuationStructurizerNode(branches[i], parent)); + mBranches[branches[i]] = branch; + } +} + +StructurizerNode *SwitchStructurizerNode::clone() const +{ + QVector branches; + for (const Vertex &e : mBranches.keys()) { + branches.append(e); + } + branches.append(mDefaultBranch.first); + SwitchStructurizerNode *newSwitch = new SwitchStructurizerNode(mId, branches, parent()); + + for (const Vertex &e : mBranches.keys()) { + newSwitch->mBranches[e] = mBranches[e]->clone(); + } + newSwitch->mDefaultBranch.second = mDefaultBranch.second->clone(); + return newSwitch; +} + +StructurizerNode::Vertex SwitchStructurizerNode::id() const +{ + return mId; +} + + +QMap SwitchStructurizerNode::branches() const +{ + return mBranches; +} + +QPair SwitchStructurizerNode::defaultBranch() const +{ + return mDefaultBranch; +} + +void SwitchStructurizerNode::dropContinuations(const Vertex &id) +{ + for (auto *&t : mBranches) { + t->dropContinuations(id); + } + mDefaultBranch.second->dropContinuations(id); +} + +bool SwitchStructurizerNode::isEqual(StructurizerNode *other) const +{ + if (other->type() != switchCase) { + return false; + } + if (mId != other->id()) { + return false; + } + for (const Vertex &e : mBranches.keys()) { + if (!static_cast(other)->mBranches.keys().contains(e) + || !static_cast(other)->mBranches[e]->isEqual(mBranches[e])) + { + return false; + } + } + if (static_cast(other)->mDefaultBranch.first != mDefaultBranch.first + || !static_cast(other)->mBranches[mDefaultBranch.first] + ->isEqual(mBranches[mDefaultBranch.first])) + { + return false; + } + return true; +} + +StructurizerNode::ConditionTree *SwitchStructurizerNode::findAllContinuations(const Vertex &id) const +{ + ConditionTree *tree = nullptr; + for (const Vertex &e : mBranches.keys()) { + if (mBranches[e]->containsContinuation(id)) { + ConditionTree *branchCondition = new ConditionTree(qMakePair(mId, e)); + ConditionTree *newCase = mBranches[e]->findAllContinuations(id); + if (newCase == nullptr) { + newCase = branchCondition; + } else { + newCase = new ConditionTree(ConditionTree::AND, branchCondition, newCase); + } + if (tree == nullptr) { + tree = newCase; + } else { + tree = new ConditionTree(ConditionTree::OR, tree, newCase); + } + } + } + if (mDefaultBranch.second->containsContinuation(id)) { + ConditionTree *branchCondition = nullptr; + for (const Vertex &e : mBranches.keys()) { + if (branchCondition == nullptr) { + branchCondition = new ConditionTree(qMakePair(mId, e)); + } else { + branchCondition = new ConditionTree(ConditionTree::OR + , branchCondition, new ConditionTree(qMakePair(mId, e))); + } + } + if (branchCondition != nullptr) { + branchCondition->invert(); + + ConditionTree *newCase = mDefaultBranch.second->findAllContinuations(id); + if (newCase == nullptr) { + newCase = branchCondition; + } else { + newCase = new ConditionTree(ConditionTree::AND, branchCondition, newCase); + } + if (tree == nullptr) { + tree = newCase; + } else { + tree = new ConditionTree(ConditionTree::OR, tree, newCase); + } + } + } + if (tree == nullptr || tree->isTrue()) { + delete tree; + return nullptr; + } + return tree; +} + +void SwitchStructurizerNode::factorize(const Vertex &id, bool force) +{ + Q_UNUSED(id) + Q_UNUSED(force) +} + +void SwitchStructurizerNode::derecursivate(const Vertex &id) +{ + Q_UNUSED(id) +} + +bool SwitchStructurizerNode::mergeConditionalBranches(const QSet &exits, const QSet &loopHeads) +{ + for (auto *&t : mBranches) { + if (t->mergeConditionalBranches(exits, loopHeads)) { + return true; + } + } + if (mDefaultBranch.second->mergeConditionalBranches(exits, loopHeads)) { + return true; + } + return false; +} + +void SwitchStructurizerNode::transformDoWhile() +{ +} + +void SwitchStructurizerNode::dropEmptyConditionals() +{ + for (auto *&t : mBranches) { + t->dropEmptyConditionals(); + } + mDefaultBranch.second->dropEmptyConditionals(); +} + +void SwitchStructurizerNode::replaceContinuation(const Vertex &id, StructurizerNode *value) +{ + for (auto *&t : mBranches) { + t->replaceContinuation(id, value); + } + mDefaultBranch.second->replaceContinuation(id, value); +} + +int SwitchStructurizerNode::numberOfConditionCalculating(const Vertex &id) const +{ + int count = mId == id ? 1 : 0; + for (auto *t : mBranches) { + count += t->numberOfConditionCalculating(id); + } + count += mDefaultBranch.second->numberOfConditionCalculating(id); + return count; +} + +bool SwitchStructurizerNode::hasBreakOnUpperLevel() const +{ + for (const auto &e : mBranches) { + if (e->hasBreakOnUpperLevel()) { + return true; + } + } + if (mDefaultBranch.second->hasBreakOnUpperLevel()) { + return true; + } + return false; +} diff --git a/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.h b/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.h new file mode 100644 index 0000000000..26190ec79f --- /dev/null +++ b/plugins/robots/generators/generatorBase/src/structurizerNodes/switchStructurizerNode.h @@ -0,0 +1,60 @@ +/* Copyright 2013-2021 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "structurizerNode.h" + +#include + +namespace generatorBase { + +class SwitchStructurizerNode : public StructurizerNode +{ +public: + explicit SwitchStructurizerNode(const Vertex &id, const QVector &branches, QObject *parent); + + Type type() const; + Vertex id() const; + QMap branches() const; + QPair defaultBranch() const; + + bool containsContinuation(const Vertex &id = Vertex()) const; + void dropContinuations(const Vertex &id); + int numberOfContinuation(const Vertex &id = Vertex()) const; + + void factorize(const Vertex &id, bool force = false); + void derecursivate(const Vertex &id); + void replaceContinuation(const Vertex &id, StructurizerNode *value); + + bool mergeConditionalBranches(const QSet &exits, const QSet &loopHeads); + void transformDoWhile(); + + ConditionTree *findAllContinuations(const Vertex &id) const; + bool isEqual(StructurizerNode *other) const; + StructurizerNode *clone() const; + int numberOfConditionCalculating(const Vertex &id) const; + + void dropEmptyConditionals(); + + bool hasBreakOnUpperLevel() const; + + bool isEmpty() const; + +protected: + const Vertex mId; + QMap mBranches; + QPair mDefaultBranch; +}; +} diff --git a/plugins/robots/generators/nxt/nxtGeneratorBase/include/nxtGeneratorBase/nxtGeneratorFactory.h b/plugins/robots/generators/nxt/nxtGeneratorBase/include/nxtGeneratorBase/nxtGeneratorFactory.h index b75c17f0b9..8b7c649102 100644 --- a/plugins/robots/generators/nxt/nxtGeneratorBase/include/nxtGeneratorBase/nxtGeneratorFactory.h +++ b/plugins/robots/generators/nxt/nxtGeneratorBase/include/nxtGeneratorBase/nxtGeneratorFactory.h @@ -28,6 +28,7 @@ class ROBOTS_NXT_GENERATOR_BASE_EXPORT NxtGeneratorFactory : public generatorBas , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName); ~NxtGeneratorFactory() override; diff --git a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.cpp b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.cpp index d47f29daef..780ea6fd6e 100644 --- a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.cpp +++ b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.cpp @@ -20,9 +20,10 @@ NxtGeneratorCustomizer::NxtGeneratorCustomizer(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks) - : mFactory(repo, errorReporter, robotModelManager, luaProcessor, generatorName) + : mFactory(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager, generatorName) , mSupportsSwitchUnstableToBreaks(supportsSwitchUnstableToBreaks) { } diff --git a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.h b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.h index e63547aee5..0a4cc95cff 100644 --- a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.h +++ b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorCustomizer.h @@ -27,6 +27,7 @@ class NxtGeneratorCustomizer : public generatorBase::GeneratorCustomizer , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName , bool supportsSwitchUnstableToBreaks); diff --git a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorFactory.cpp b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorFactory.cpp index 6bb2f3f87a..157bf61ec8 100644 --- a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorFactory.cpp +++ b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtGeneratorFactory.cpp @@ -32,8 +32,9 @@ NxtGeneratorFactory::NxtGeneratorFactory(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName) - : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor) + : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager) , mGeneratorName(generatorName) , mImages(pathsToTemplates()) { diff --git a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtMasterGeneratorBase.cpp b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtMasterGeneratorBase.cpp index d4e89ae6ab..3442e44659 100644 --- a/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtMasterGeneratorBase.cpp +++ b/plugins/robots/generators/nxt/nxtGeneratorBase/src/nxtMasterGeneratorBase.cpp @@ -34,7 +34,7 @@ NxtMasterGeneratorBase::NxtMasterGeneratorBase(const qrRepo::RepoApi &repo generatorBase::GeneratorCustomizer *NxtMasterGeneratorBase::createCustomizer() { return new NxtGeneratorCustomizer(mRepo, mErrorReporter, mRobotModelManager, *createLuaProcessor() - , mGeneratorName, supportsSwitchUnstableToBreaks()); + , *mReadableLabelManager , mGeneratorName, supportsSwitchUnstableToBreaks()); } void NxtMasterGeneratorBase::beforeGeneration() diff --git a/plugins/robots/generators/nxt/nxtOsekCGenerator/templates.qrc b/plugins/robots/generators/nxt/nxtOsekCGenerator/templates.qrc index a1b985edbe..0aea3b82c6 100644 --- a/plugins/robots/generators/nxt/nxtOsekCGenerator/templates.qrc +++ b/plugins/robots/generators/nxt/nxtOsekCGenerator/templates.qrc @@ -3,6 +3,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/nxt/nxtOsekCGenerator/templates/pass.t b/plugins/robots/generators/nxt/nxtOsekCGenerator/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/nxt/nxtRussianCGenerator/templates.qrc b/plugins/robots/generators/nxt/nxtRussianCGenerator/templates.qrc index 9f9008736f..c845335fd9 100644 --- a/plugins/robots/generators/nxt/nxtRussianCGenerator/templates.qrc +++ b/plugins/robots/generators/nxt/nxtRussianCGenerator/templates.qrc @@ -3,6 +3,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/nxt/nxtRussianCGenerator/templates/pass.t b/plugins/robots/generators/nxt/nxtRussianCGenerator/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGenerator.pro b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGenerator.pro index 7a46e3fe6a..1e67e6c042 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGenerator.pro +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGenerator.pro @@ -44,7 +44,6 @@ HEADERS += \ $$PWD/communicator/communicatorInterface.h \ $$PWD/communicator/communicationManager.h \ $$PWD/communicator/httpCommunicator.h \ - $$PWD/generators/gotoLabelManager.h \ $$PWD/generators/pioneerStateMachineGenerator.h \ $$PWD/generators/randomFunctionChecker.h \ $$PWD/generators/semanticTreeManager.h \ @@ -78,7 +77,6 @@ SOURCES += \ $$PWD/pioneerLuaMasterGenerator.cpp \ $$PWD/communicator/communicationManager.cpp \ $$PWD/communicator/httpCommunicator.cpp \ - $$PWD/generators/gotoLabelManager.cpp \ $$PWD/generators/pioneerStateMachineGenerator.cpp \ $$PWD/generators/randomFunctionChecker.cpp \ $$PWD/generators/semanticTreeManager.cpp \ diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.cpp b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.cpp index ba46327adf..8721ce6b9c 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.cpp +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.cpp @@ -22,8 +22,8 @@ PioneerLuaGeneratorCustomizer::PioneerLuaGeneratorCustomizer(const qrRepo::RepoA , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName - , GotoLabelManager &gotoLabelManager , bool supportsSwitchUnstableToBreaks) : mFactory( new PioneerLuaGeneratorFactory( @@ -31,8 +31,8 @@ PioneerLuaGeneratorCustomizer::PioneerLuaGeneratorCustomizer(const qrRepo::RepoA , errorReporter , robotModelManager , luaProcessor + , readableLabelManager , generatorName - , gotoLabelManager )) , mSupportsSwitchUnstableToBreaks(supportsSwitchUnstableToBreaks) { diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.h b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.h index c10ceebb95..b2b80275a0 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.h +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorCustomizer.h @@ -22,7 +22,6 @@ namespace pioneer { namespace lua { class PioneerLuaGeneratorFactory; -class GotoLabelManager; /// Customizer for Pioneer generator. Provides factory that can create simple generators for blocks. class PioneerLuaGeneratorCustomizer : public generatorBase::GeneratorCustomizer @@ -32,8 +31,8 @@ class PioneerLuaGeneratorCustomizer : public generatorBase::GeneratorCustomizer , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QString &generatorName - , GotoLabelManager &gotoLabelManager , bool supportsSwitchUnstableToBreaks); generatorBase::GeneratorFactoryBase *factory() override; diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.cpp b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.cpp index b2a29135af..4b364e3152 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.cpp +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.cpp @@ -20,7 +20,7 @@ #include "parts/tofPart.h" #include "parts/magnetPart.h" #include "parts/randomGeneratorPart.h" -#include "generators/gotoLabelManager.h" +#include "src/readableLabelManager.h" #include "simpleGenerators/endOfHandlerGenerator.h" #include "simpleGenerators/geoLandingGenerator.h" #include "simpleGenerators/geoTakeoffGenerator.h" @@ -45,11 +45,10 @@ PioneerLuaGeneratorFactory::PioneerLuaGeneratorFactory(const qrRepo::RepoApi &re , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor - , const QString &generatorName - , GotoLabelManager &gotoLabelManager) - : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor) + , generatorBase::ReadableLabelManager &readableLabelManager + , const QString &generatorName) + : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager) , mGeneratorName(generatorName) - , mGotoLabelManager(gotoLabelManager) { } @@ -132,13 +131,13 @@ RandomGeneratorPart& PioneerLuaGeneratorFactory::randomGeneratorPart() generatorBase::simple::AbstractSimpleGenerator *PioneerLuaGeneratorFactory::labelGenerator(const qReal::Id &id , generatorBase::GeneratorCustomizer &customizer) { - return new LabelGenerator(mRepo, customizer, id, this, mGotoLabelManager); + return new LabelGenerator(mRepo, customizer, id, this, mReadableLabelManager); } generatorBase::simple::AbstractSimpleGenerator *PioneerLuaGeneratorFactory::gotoSimpleGenerator(const qReal::Id &id , generatorBase::GeneratorCustomizer &customizer) { - return new GotoGenerator(mRepo, customizer, id, this, mGotoLabelManager); + return new GotoGenerator(mRepo, customizer, id, this, mReadableLabelManager); } QList PioneerLuaGeneratorFactory::initTerminateGenerators() diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.h b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.h index 6760e543a6..923dc43edf 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.h +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaGeneratorFactory.h @@ -19,7 +19,6 @@ namespace pioneer { namespace lua { -class GotoLabelManager; class LedPart; class TofPart; class MagnetPart; @@ -33,8 +32,8 @@ class PioneerLuaGeneratorFactory : public generatorBase::GeneratorFactoryBase , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor - , const QString &generatorName - , GotoLabelManager &gotoLabelManager); + , generatorBase::ReadableLabelManager &readableLabelManager + , const QString &generatorName); ~PioneerLuaGeneratorFactory() override; @@ -72,10 +71,6 @@ class PioneerLuaGeneratorFactory : public generatorBase::GeneratorFactoryBase /// Generator name is used as a prefix to a path to templates in resources. const QString mGeneratorName; - /// Storage and generator for human-readable goto labels. Used in label ganerator and goto generator created by - /// this factory. - GotoLabelManager &mGotoLabelManager; - /// Generator part that tracks LED usage and initializes it if needed. QScopedPointer mLedPart; diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.cpp b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.cpp index 293bb0467b..abaa6f744b 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.cpp +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.cpp @@ -29,7 +29,6 @@ #include "pioneerLuaGeneratorCustomizer.h" #include "pioneerLuaGeneratorFactory.h" #include "generators/pioneerStateMachineGenerator.h" -#include "generators/gotoLabelManager.h" #include "generators/randomFunctionChecker.h" using namespace pioneer::lua; @@ -48,7 +47,6 @@ PioneerLuaMasterGenerator::PioneerLuaMasterGenerator(const qrRepo::RepoApi &repo : MasterGeneratorBase(repo, errorReporter, robotModelManager, textLanguage, parserErrorReporter, diagramId) , mGeneratorName(generatorName) , mMetamodel(metamodel) - , mGotoLabelManager(new GotoLabelManager()) { } @@ -82,8 +80,8 @@ generatorBase::GeneratorCustomizer *PioneerLuaMasterGenerator::createCustomizer( , mErrorReporter , mRobotModelManager , *createLuaProcessor() + , *mReadableLabelManager , mGeneratorName - , *mGotoLabelManager , supportsSwitchUnstableToBreaks()); } @@ -114,7 +112,7 @@ QString PioneerLuaMasterGenerator::generate(const QString &indentString) QLOG_INFO() << "Starting Pioneer program generation to " << mProjectDir; - mGotoLabelManager->reinit(); + mReadableLabelManager->reinit(); beforeGeneration(); diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.h b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.h index cf64ad7d9e..2445e56233 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.h +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/pioneerLuaMasterGenerator.h @@ -15,6 +15,7 @@ #pragma once #include +#include "src/readableLabelManager.h" #include @@ -26,7 +27,6 @@ namespace pioneer { namespace lua { class PioneerStateMachineGenerator; -class GotoLabelManager; class RandomFunctionChecker; /// Main generator that directs generation process (mainly by configuring its base class that does actual job). @@ -66,9 +66,6 @@ class PioneerLuaMasterGenerator : public generatorBase::MasterGeneratorBase /// for a node. const qReal::EditorManagerInterface &mMetamodel; - /// Storage and generator for human-readable goto labels. - QScopedPointer mGotoLabelManager; - /// Object that tracks "random()" function usage in Lua code of properties, to be able to properly initialize /// random number generator if needed. QScopedPointer mRandomFunctionChecker; diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.cpp b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.cpp index 8e40ec5b97..b77dce301f 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.cpp +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.cpp @@ -17,8 +17,6 @@ #include #include -#include "generators/gotoLabelManager.h" - using namespace pioneer::lua; using namespace generatorBase::simple; @@ -26,9 +24,9 @@ GotoGenerator::GotoGenerator(const qrRepo::RepoApi &repo , generatorBase::GeneratorCustomizer &customizer , const qReal::Id &id , QObject *parent - , GotoLabelManager &gotoLabelManager) + , generatorBase::ReadableLabelManager &readableLabelManager) : BindingGenerator(repo, customizer, id, "goto.t" - , { Binding::createStaticConverting("@@ID@@", gotoLabelManager.labelFor(id) + , { Binding::createStaticConverting("@@ID@@", readableLabelManager.labelFor(id) , customizer.factory()->nameNormalizerConverter()) } , parent) { diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.h b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.h index d02ed46477..10589ee008 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.h +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/gotoGenerator.h @@ -15,12 +15,11 @@ #pragma once #include +#include "src/readableLabelManager.h" namespace pioneer { namespace lua { -class GotoLabelManager; - /// Generates goto to a human-readable label. class GotoGenerator : public generatorBase::simple::BindingGenerator { @@ -29,7 +28,7 @@ class GotoGenerator : public generatorBase::simple::BindingGenerator , generatorBase::GeneratorCustomizer &customizer , const qReal::Id &id , QObject *parent - , GotoLabelManager &gotoLabelManager + , generatorBase::ReadableLabelManager &readableLabelManager ); }; diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.cpp b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.cpp index 838626bc86..94a61381b6 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.cpp +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.cpp @@ -17,8 +17,6 @@ #include #include -#include "generators/gotoLabelManager.h" - using namespace pioneer::lua; using namespace generatorBase::simple; @@ -26,11 +24,11 @@ LabelGenerator::LabelGenerator(const qrRepo::RepoApi &repo , generatorBase::GeneratorCustomizer &customizer , const qReal::Id &id , QObject *parent - , GotoLabelManager &gotoLabelManager) + , generatorBase::ReadableLabelManager &readableLabelManager) : BindingGenerator(repo, customizer, id, "label.t" , { Binding::createStaticConverting( "@@ID@@" - , gotoLabelManager.labelFor(id) + , readableLabelManager.labelFor(id) , customizer.factory()->nameNormalizerConverter() ) } diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.h b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.h index fbcf4fb7f3..535ad23709 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.h +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/simpleGenerators/labelGenerator.h @@ -15,12 +15,11 @@ #pragma once #include +#include "src/readableLabelManager.h" namespace pioneer { namespace lua { -class GotoLabelManager; - /// Generates human-readable label for a node. class LabelGenerator : public generatorBase::simple::BindingGenerator { @@ -29,7 +28,7 @@ class LabelGenerator : public generatorBase::simple::BindingGenerator , generatorBase::GeneratorCustomizer &customizer , const qReal::Id &id , QObject *parent - , GotoLabelManager &gotoLabelManager); + , generatorBase::ReadableLabelManager &readableLabelManager); }; } diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates.qrc b/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates.qrc index 6a865c8698..90ae1082ef 100644 --- a/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates.qrc +++ b/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates.qrc @@ -3,6 +3,7 @@ templates/break.t templates/comment.t templates/continue.t + templates/pass.t templates/endOfHandler.t templates/finalNodeMain.t templates/finalNodeSubprogram.t diff --git a/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates/pass.t b/plugins/robots/generators/pioneer/pioneerLuaGenerator/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates.qrc b/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates.qrc index f6b9fe3813..5a3efcc71c 100644 --- a/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates.qrc +++ b/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates.qrc @@ -3,6 +3,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates/pass.t b/plugins/robots/generators/trik/trikFSharpGeneratorLibrary/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.cpp b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.cpp index 5e11fe8e7b..7de66108d0 100644 --- a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.cpp +++ b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.cpp @@ -20,9 +20,10 @@ TrikGeneratorCustomizer::TrikGeneratorCustomizer(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QStringList &pathsToTemplates , bool supportsSwitchUnstableToBreaks) - : mFactory(repo, errorReporter, robotModelManager, luaProcessor, pathsToTemplates) + : mFactory(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager, pathsToTemplates) , mSupportsSwitchUnstableToBreaks(supportsSwitchUnstableToBreaks) { } diff --git a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.h b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.h index 94ee1cf40a..2df5767663 100644 --- a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.h +++ b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorCustomizer.h @@ -27,6 +27,7 @@ class TrikGeneratorCustomizer : public generatorBase::GeneratorCustomizer , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QStringList &pathsToTemplates , bool supportsSwitchUnstableToBreaks); diff --git a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.cpp b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.cpp index 713ee112c0..74b10e77ab 100644 --- a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.cpp +++ b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.cpp @@ -64,8 +64,9 @@ TrikGeneratorFactory::TrikGeneratorFactory(const qrRepo::RepoApi &repo , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QStringList &pathsToTemplates) - : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor) + : GeneratorFactoryBase(repo, errorReporter, robotModelManager, luaProcessor, readableLabelManager) , mPathsToTemplates(pathsToTemplates) { mDeviceVariables.reset(new trik::parts::TrikDeviceVariables()); diff --git a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.h b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.h index 4ca4149fb1..32c62cadd6 100644 --- a/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.h +++ b/plugins/robots/generators/trik/trikGeneratorBase/src/trikGeneratorFactory.h @@ -26,6 +26,7 @@ class TrikGeneratorFactory : public generatorBase::GeneratorFactoryBase , qReal::ErrorReporterInterface &errorReporter , const kitBase::robotModel::RobotModelManagerInterface &robotModelManager , generatorBase::lua::LuaProcessor &luaProcessor + , generatorBase::ReadableLabelManager &readableLabelManager , const QStringList &pathsToTemplates); ~TrikGeneratorFactory() override; diff --git a/plugins/robots/generators/trik/trikGeneratorBase/src/trikMasterGeneratorBase.cpp b/plugins/robots/generators/trik/trikGeneratorBase/src/trikMasterGeneratorBase.cpp index c1b1e4bf45..dcca8c49f5 100644 --- a/plugins/robots/generators/trik/trikGeneratorBase/src/trikMasterGeneratorBase.cpp +++ b/plugins/robots/generators/trik/trikGeneratorBase/src/trikMasterGeneratorBase.cpp @@ -32,5 +32,5 @@ TrikMasterGeneratorBase::TrikMasterGeneratorBase(const qrRepo::RepoApi &repo generatorBase::GeneratorCustomizer *TrikMasterGeneratorBase::createCustomizer() { return new TrikGeneratorCustomizer(mRepo, mErrorReporter - , mRobotModelManager, *createLuaProcessor(), mPathsToTemplates, supportsSwitchUnstableToBreaks()); + , mRobotModelManager, *createLuaProcessor(), *mReadableLabelManager, mPathsToTemplates, supportsSwitchUnstableToBreaks()); } diff --git a/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates.qrc b/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates.qrc index cb0c98061e..b2a88a806d 100644 --- a/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates.qrc +++ b/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates.qrc @@ -4,6 +4,7 @@ templates/break.t templates/comment.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates/pass.t b/plugins/robots/generators/trik/trikPascalABCGeneratorLibrary/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates.qrc b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates.qrc index b6fa8dc39a..d938ea1201 100644 --- a/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates.qrc +++ b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates.qrc @@ -3,6 +3,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/pass.t b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/pass.t new file mode 100644 index 0000000000..2ae28399f5 --- /dev/null +++ b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/pass.t @@ -0,0 +1 @@ +pass diff --git a/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/switch/middle.t b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/switch/middle.t index a66bf0bc9e..fb25ea9699 100644 --- a/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/switch/middle.t +++ b/plugins/robots/generators/trik/trikPythonGeneratorLibrary/templates/switch/middle.t @@ -1,2 +1,2 @@ -else: if (@@CONDITION@@): +elif (@@CONDITION@@): @@BODY@@ diff --git a/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates.qrc b/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates.qrc index e4a7d38410..a379cc1f3b 100644 --- a/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates.qrc +++ b/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates.qrc @@ -3,6 +3,7 @@ templates/beep.t templates/break.t templates/continue.t + templates/pass.t templates/finalNodeMain.t templates/finalNodeSubprogram.t templates/function.t diff --git a/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates/pass.t b/plugins/robots/generators/trik/trikQtsGeneratorLibrary/templates/pass.t new file mode 100644 index 0000000000..e69de29bb2 diff --git a/qrtranslations/fr/plugins/robots/generatorBase_fr.ts b/qrtranslations/fr/plugins/robots/generatorBase_fr.ts index bf63c26203..6fe98607b6 100644 --- a/qrtranslations/fr/plugins/robots/generatorBase_fr.ts +++ b/qrtranslations/fr/plugins/robots/generatorBase_fr.ts @@ -14,7 +14,7 @@ /* ERREUR SELECTIONNEZ LE TYPE DU CAPTEUR */ - + There is no opened diagram Il n'y a pas de diagramme d'ouvert @@ -136,7 +136,7 @@ generatorBase::MasterGeneratorBase - + This diagram cannot be generated into the structured code. Generating it into the code with 'goto' statements. Ce diagramme ne peut pas être transformé en code structuré. Le code contenant 'goto' sera généré. diff --git a/qrtranslations/ru/plugins/robots/generatorBase_ru.ts b/qrtranslations/ru/plugins/robots/generatorBase_ru.ts index b366e7348f..f2c94a4192 100644 --- a/qrtranslations/ru/plugins/robots/generatorBase_ru.ts +++ b/qrtranslations/ru/plugins/robots/generatorBase_ru.ts @@ -95,7 +95,7 @@ Неизвестный блок - + There is no opened diagram Сначала откройте диаграмму @@ -137,7 +137,7 @@ generatorBase::MasterGeneratorBase - + This diagram cannot be generated into the structured code. Generating it into the code with 'goto' statements. Данная диаграмма не может быть сгенерирована в структурированный код. Генерирую код с 'goto'. diff --git a/qrtranslations/ru/plugins/robots/pioneerLuaGenerator_ru.ts b/qrtranslations/ru/plugins/robots/pioneerLuaGenerator_ru.ts index 18eb381dfe..6b2e4a8473 100644 --- a/qrtranslations/ru/plugins/robots/pioneerLuaGenerator_ru.ts +++ b/qrtranslations/ru/plugins/robots/pioneerLuaGenerator_ru.ts @@ -88,7 +88,7 @@ QObject - + There is no opened diagram Диаграмма не открыта diff --git a/qrutils/graphUtils/deepFirstSearcher.cpp b/qrutils/graphUtils/deepFirstSearcher.cpp index 5419ac0cf6..2e04c6f25a 100644 --- a/qrutils/graphUtils/deepFirstSearcher.cpp +++ b/qrutils/graphUtils/deepFirstSearcher.cpp @@ -69,7 +69,7 @@ void DeepFirstSearcher::dfs(const Id &id, const QList &visit } for (const LinkInfo &link : linkInfos) { - if (!link.targetVisited && link.connected && !mSearchTerminated) { + if (!mVisitedNodes.contains(link.target) && link.connected && !mSearchTerminated) { dfs(link.target, visitors); } }