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