aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/libparser
diff options
context:
space:
mode:
authorRenaud G <renaud@rolisteam.org>2022-04-29 10:48:09 +0200
committerRenaud G <renaud@rolisteam.org>2022-04-29 10:48:09 +0200
commit07c5f6ec23fcf9237a24e71adcfacabce677f818 (patch)
tree588e8c5f82b9163181fad3581f610e6f1d88cba4 /src/libparser
parenta9153f1615a842cfb9e9bcda4d9071e202618569 (diff)
downloadOneRoll-07c5f6ec23fcf9237a24e71adcfacabce677f818.tar.gz
OneRoll-07c5f6ec23fcf9237a24e71adcfacabce677f818.zip
Change file organization.
Diffstat (limited to 'src/libparser')
-rw-r--r--src/libparser/CMakeLists.txt131
-rw-r--r--src/libparser/booleancondition.cpp231
-rw-r--r--src/libparser/booleancondition.h61
-rw-r--r--src/libparser/compositevalidator.cpp196
-rw-r--r--src/libparser/compositevalidator.h64
-rw-r--r--src/libparser/dicealias.cpp231
-rw-r--r--src/libparser/diceparser.cpp271
-rw-r--r--src/libparser/diceparser.pc.in12
-rw-r--r--src/libparser/diceroller.cpp227
-rw-r--r--src/libparser/die.cpp257
-rw-r--r--src/libparser/die.h160
-rw-r--r--src/libparser/highlightdice.cpp110
-rw-r--r--src/libparser/include/diceparser/dicealias.h122
-rw-r--r--src/libparser/include/diceparser/diceparser.h130
-rw-r--r--src/libparser/include/diceparser/diceparser_global.h11
-rw-r--r--src/libparser/include/diceparser/diceparserhelper.h96
-rw-r--r--src/libparser/include/diceparser/highlightdice.h68
-rw-r--r--src/libparser/include/diceparser/parsingtoolbox.h284
-rw-r--r--src/libparser/include/diceparser_qobject/diceparser_qobject_global.h11
-rw-r--r--src/libparser/include/diceparser_qobject/diceroller.h74
-rw-r--r--src/libparser/include/diceparser_qobject/qmltypesregister.h27
-rw-r--r--src/libparser/node/allsamenode.cpp86
-rw-r--r--src/libparser/node/allsamenode.h33
-rw-r--r--src/libparser/node/bind.cpp114
-rw-r--r--src/libparser/node/bind.h50
-rw-r--r--src/libparser/node/countexecutenode.cpp76
-rw-r--r--src/libparser/node/countexecutenode.h50
-rw-r--r--src/libparser/node/dicerollernode.cpp121
-rw-r--r--src/libparser/node/dicerollernode.h63
-rw-r--r--src/libparser/node/executionnode.cpp101
-rw-r--r--src/libparser/node/executionnode.h102
-rw-r--r--src/libparser/node/explodedicenode.cpp117
-rw-r--r--src/libparser/node/explodedicenode.h29
-rw-r--r--src/libparser/node/filternode.cpp94
-rw-r--r--src/libparser/node/filternode.h40
-rw-r--r--src/libparser/node/forloopnode.cpp103
-rw-r--r--src/libparser/node/forloopnode.h36
-rw-r--r--src/libparser/node/groupnode.cpp312
-rw-r--r--src/libparser/node/groupnode.h72
-rw-r--r--src/libparser/node/helpnode.cpp142
-rw-r--r--src/libparser/node/helpnode.h69
-rw-r--r--src/libparser/node/ifnode.cpp354
-rw-r--r--src/libparser/node/ifnode.h117
-rw-r--r--src/libparser/node/jumpbackwardnode.cpp168
-rw-r--r--src/libparser/node/jumpbackwardnode.h68
-rw-r--r--src/libparser/node/keepdiceexecnode.cpp131
-rw-r--r--src/libparser/node/keepdiceexecnode.h47
-rw-r--r--src/libparser/node/listaliasnode.cpp85
-rw-r--r--src/libparser/node/listaliasnode.h64
-rw-r--r--src/libparser/node/listsetrollnode.cpp190
-rw-r--r--src/libparser/node/listsetrollnode.h62
-rw-r--r--src/libparser/node/mergenode.cpp150
-rw-r--r--src/libparser/node/mergenode.h50
-rw-r--r--src/libparser/node/node.pri33
-rw-r--r--src/libparser/node/numbernode.cpp84
-rw-r--r--src/libparser/node/numbernode.h47
-rw-r--r--src/libparser/node/occurencecountnode.cpp185
-rw-r--r--src/libparser/node/occurencecountnode.h60
-rw-r--r--src/libparser/node/paintnode.cpp125
-rw-r--r--src/libparser/node/paintnode.h60
-rw-r--r--src/libparser/node/parenthesesnode.cpp119
-rw-r--r--src/libparser/node/parenthesesnode.h46
-rw-r--r--src/libparser/node/repeaternode.cpp162
-rw-r--r--src/libparser/node/repeaternode.h48
-rw-r--r--src/libparser/node/replacevaluenode.cpp134
-rw-r--r--src/libparser/node/replacevaluenode.h50
-rw-r--r--src/libparser/node/rerolldicenode.cpp148
-rw-r--r--src/libparser/node/rerolldicenode.h72
-rw-r--r--src/libparser/node/scalaroperatornode.cpp286
-rw-r--r--src/libparser/node/scalaroperatornode.h127
-rw-r--r--src/libparser/node/sortresult.cpp148
-rw-r--r--src/libparser/node/sortresult.h69
-rw-r--r--src/libparser/node/splitnode.cpp93
-rw-r--r--src/libparser/node/splitnode.h44
-rw-r--r--src/libparser/node/startingnode.cpp61
-rw-r--r--src/libparser/node/startingnode.h57
-rw-r--r--src/libparser/node/stringnode.cpp58
-rw-r--r--src/libparser/node/stringnode.h29
-rw-r--r--src/libparser/node/switchcasenode.cpp149
-rw-r--r--src/libparser/node/switchcasenode.h50
-rw-r--r--src/libparser/node/uniquenode.cpp93
-rw-r--r--src/libparser/node/uniquenode.h44
-rw-r--r--src/libparser/node/valueslistnode.cpp62
-rw-r--r--src/libparser/node/valueslistnode.h24
-rw-r--r--src/libparser/node/variablenode.cpp112
-rw-r--r--src/libparser/node/variablenode.h35
-rw-r--r--src/libparser/operationcondition.cpp167
-rw-r--r--src/libparser/operationcondition.h61
-rw-r--r--src/libparser/parsingtoolbox.cpp2641
-rw-r--r--src/libparser/qmltypesregister.cpp38
-rw-r--r--src/libparser/range.cpp121
-rw-r--r--src/libparser/range.h60
-rw-r--r--src/libparser/result/diceresult.cpp193
-rw-r--r--src/libparser/result/diceresult.h97
-rw-r--r--src/libparser/result/result.cpp86
-rw-r--r--src/libparser/result/result.h96
-rw-r--r--src/libparser/result/scalarresult.cpp58
-rw-r--r--src/libparser/result/scalarresult.h59
-rw-r--r--src/libparser/result/stringresult.cpp117
-rw-r--r--src/libparser/result/stringresult.h45
-rw-r--r--src/libparser/validator.cpp131
-rw-r--r--src/libparser/validator.h107
-rw-r--r--src/libparser/validatorlist.cpp453
-rw-r--r--src/libparser/validatorlist.h99
104 files changed, 13613 insertions, 0 deletions
diff --git a/src/libparser/CMakeLists.txt b/src/libparser/CMakeLists.txt
new file mode 100644
index 0000000..e477696
--- /dev/null
+++ b/src/libparser/CMakeLists.txt
@@ -0,0 +1,131 @@
+cmake_minimum_required(VERSION 3.16)
+
+set(QT_REQUIRED_VERSION "6.2.0")
+set(QT_VERSION_MAJOR "6")
+find_package(Qt${QT_VERSION_MAJOR} ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Test Gui Svg)
+find_package(Qt${QT_VERSION_MAJOR} ${QT_REQUIRED_VERSION} CONFIG COMPONENTS Qml Concurrent)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} result node)
+
+set(dice_header_path include/diceparser)
+
+set(dice_public_headers ${dice_header_path}/diceparser_global.h
+${dice_header_path}/dicealias.h
+${dice_header_path}/diceparser.h
+${dice_header_path}/diceparserhelper.h
+${dice_header_path}/highlightdice.h
+${dice_header_path}/parsingtoolbox.h # should no be public…
+)
+
+
+SET( dice_sources
+ ${CMAKE_CURRENT_SOURCE_DIR}/diceparser.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/range.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/booleancondition.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/validator.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/validatorlist.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/operationcondition.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/die.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/parsingtoolbox.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/dicealias.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/result/result.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/result/scalarresult.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/result/stringresult.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/result/diceresult.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/countexecutenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/dicerollernode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/executionnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/explodedicenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/helpnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/allsamenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/mergenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/jumpbackwardnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/keepdiceexecnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/listaliasnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/listsetrollnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/numbernode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/parenthesesnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/paintnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/rerolldicenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/scalaroperatornode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/sortresult.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/startingnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/filternode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/stringnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/ifnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/splitnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/groupnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/bind.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/occurencecountnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/uniquenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/highlightdice.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/variablenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/valueslistnode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/repeaternode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/switchcasenode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/node/replacevaluenode.cpp
+)
+
+IF(STATIC_BUILD)
+ add_library(diceparser_static STATIC ${dice_sources} )
+ target_include_directories(diceparser_static PRIVATE include)
+ target_link_libraries(diceparser_static PUBLIC Qt6::Core Qt6::Gui Qt6::Svg)
+ install(TARGETS diceparser_static
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()
+
+
+
+add_library(diceparser_shared SHARED ${dice_sources} ${dice_public_headers})
+set_target_properties(diceparser_shared PROPERTIES PUBLIC_HEADER "${public_header_widget}")
+target_compile_definitions(diceparser_shared PRIVATE DICEPARSER_LIBRARY)
+
+target_include_directories(diceparser_shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
+
+SET_TARGET_PROPERTIES(diceparser_shared PROPERTIES OUTPUT_NAME diceparser CLEAN_DIRECT_OUTPUT 1)
+target_link_libraries(diceparser_shared PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Svg)
+
+set_target_properties(diceparser_shared PROPERTIES VERSION ${PROJECT_VERSION})
+set_target_properties(diceparser_shared PROPERTIES SOVERSION 1)
+
+
+include(GNUInstallDirs)
+
+
+configure_file(diceparser.pc.in diceparser.pc @ONLY)
+
+install(TARGETS diceparser_shared
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/diceparser.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
+
+if(Qt${QT_VERSION_MAJOR}Qml_FOUND)
+ set(dice_header_qobject include/diceparser_qobject/diceparser_qobject_global.h include/diceparser_qobject/qmltypesregister.h include/diceparser_qobject/diceroller.h)
+ set(dice_source_qobject qmltypesregister.cpp diceroller.cpp)
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_AUTOUIC ON)
+ set(CMAKE_AUTORCC ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ add_library(diceparser_qobject SHARED ${dice_header_qobject} ${dice_source_qobject})
+ set_target_properties(diceparser_qobject PROPERTIES PUBLIC_HEADER "${dice_header_qobject}")
+ target_compile_definitions(diceparser_qobject PRIVATE DICEPARSER_QOBJECT_LIBRARY)
+ target_link_libraries(diceparser_qobject PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Concurrent PRIVATE diceparser_shared)
+ message("Messages diceparser ${CMAKE_CURRENT_SOURCE_DIR}/include")
+
+ target_include_directories(diceparser_qobject PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
+
+
+ install(TARGETS diceparser_qobject
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+endif()
+
+
+
diff --git a/src/libparser/booleancondition.cpp b/src/libparser/booleancondition.cpp
new file mode 100644
index 0000000..91be35c
--- /dev/null
+++ b/src/libparser/booleancondition.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "booleancondition.h"
+
+Dice::CONDITION_STATE testEqual(bool insideRange, const std::pair<qint64, qint64>& range)
+{
+ if(!insideRange)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(insideRange && (range.first == range.second))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testGreatherThan(qint64 value, const std::pair<qint64, qint64>& range)
+{
+ if(value >= std::max(range.first, range.second))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(value < std::min(range.first, range.second))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testLesserThan(qint64 value, const std::pair<qint64, qint64>& range)
+{
+ if(value <= std::min(range.first, range.second))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(value > std::max(range.first, range.second))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testGreaterOrEqual(qint64 value, const std::pair<qint64, qint64>& range)
+{
+ if(value > std::max(range.first, range.second))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(value <= std::min(range.first, range.second))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testLesserOrEqual(qint64 value, const std::pair<qint64, qint64>& range)
+{
+ if(value < std::min(range.first, range.second))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(value >= std::max(range.first, range.second))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testDifferent(bool inside, const std::pair<qint64, qint64>& range)
+{
+ if(inside && (range.first == range.second))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(!inside)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+BooleanCondition::BooleanCondition() : m_operator(Dice::CompareOperator::Equal) {}
+
+BooleanCondition::~BooleanCondition()
+{
+ if(m_value != nullptr)
+ {
+ delete m_value;
+ m_value= nullptr;
+ }
+}
+qint64 BooleanCondition::hasValid(Die* b, bool recursive, bool unhighlight) const
+{
+ QList<qint64> listValues;
+ if(m_conditionType == Dice::OnEachValue)
+ {
+ listValues.append(b->getValue());
+ }
+ else if(recursive)
+ {
+ listValues= b->getListValue();
+ }
+ else
+ {
+ listValues.append(b->getLastRolledValue());
+ }
+
+ qint64 sum= 0;
+ auto valueScalar= valueToScalar();
+ for(qint64& value : listValues)
+ {
+ switch(m_operator)
+ {
+ case Dice::CompareOperator::Equal:
+ sum+= (value == valueScalar) ? 1 : 0;
+ break;
+ case Dice::CompareOperator::GreaterThan:
+ sum+= (value > valueScalar) ? 1 : 0;
+ break;
+ case Dice::CompareOperator::LesserThan:
+ sum+= (value < valueScalar) ? 1 : 0;
+ break;
+ case Dice::CompareOperator::GreaterOrEqual:
+ sum+= (value >= valueScalar) ? 1 : 0;
+ break;
+ case Dice::CompareOperator::LesserOrEqual:
+ sum+= (value <= valueScalar) ? 1 : 0;
+ break;
+ case Dice::CompareOperator::Different:
+ sum+= (value != valueScalar) ? 1 : 0;
+ break;
+ }
+ }
+ if((unhighlight) && (sum == 0))
+ {
+ b->setHighlighted(false);
+ }
+ else
+ {
+ b->setHighlighted(true);
+ }
+
+ return sum;
+}
+
+void BooleanCondition::setOperator(Dice::CompareOperator m)
+{
+ m_operator= m;
+}
+
+void BooleanCondition::setValueNode(ExecutionNode* v)
+{
+ m_value= v;
+}
+QString BooleanCondition::toString()
+{
+ QString str("");
+ switch(m_operator)
+ {
+ case Dice::CompareOperator::Equal:
+ str.append(QStringLiteral("="));
+ break;
+ case Dice::CompareOperator::GreaterThan:
+ str.append(QStringLiteral(">"));
+ break;
+ case Dice::CompareOperator::LesserThan:
+ str.append(QStringLiteral("<"));
+ break;
+ case Dice::CompareOperator::GreaterOrEqual:
+ str.append(QStringLiteral(">="));
+ break;
+ case Dice::CompareOperator::LesserOrEqual:
+ str.append(QStringLiteral("<="));
+ break;
+ case Dice::CompareOperator::Different:
+ str.append(QStringLiteral("!="));
+ break;
+ }
+ return QStringLiteral("[%1%2]").arg(str).arg(valueToScalar());
+}
+
+Dice::CONDITION_STATE BooleanCondition::isValidRangeSize(const std::pair<qint64, qint64>& range) const
+{
+ Dice::CONDITION_STATE state;
+ auto valueScalar= valueToScalar();
+ qint64 boundValue= qBound(range.first, valueScalar, range.second);
+ bool isInsideRange= (boundValue == valueScalar);
+ switch(m_operator)
+ {
+ case Dice::CompareOperator::Equal:
+ state= testEqual(isInsideRange, range); //(isInsideRange && (range.first != range.second)) ? ;
+ break;
+ case Dice::CompareOperator::GreaterThan:
+ state= testGreatherThan(valueScalar, range);
+ break;
+ case Dice::CompareOperator::LesserThan:
+ state= testLesserThan(valueScalar, range);
+ break;
+ case Dice::CompareOperator::GreaterOrEqual:
+ state= testGreaterOrEqual(valueScalar, range);
+ break;
+ case Dice::CompareOperator::LesserOrEqual:
+ state= testLesserOrEqual(valueScalar, range);
+ break;
+ case Dice::CompareOperator::Different:
+ state= testDifferent(isInsideRange, range);
+ break;
+ }
+ return state;
+}
+Validator* BooleanCondition::getCopy() const
+{
+ BooleanCondition* val= new BooleanCondition();
+ val->setOperator(m_operator);
+ val->setValueNode(m_value->getCopy());
+ return val;
+}
+qint64 BooleanCondition::valueToScalar() const
+{
+ if(m_value == nullptr)
+ return 0;
+
+ m_value->run(nullptr);
+ auto result= m_value->getResult();
+ if(result)
+ return result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ else
+ return 0;
+}
diff --git a/src/libparser/booleancondition.h b/src/libparser/booleancondition.h
new file mode 100644
index 0000000..d49c5fe
--- /dev/null
+++ b/src/libparser/booleancondition.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef BOOLEANCONDITION_H
+#define BOOLEANCONDITION_H
+
+#include "diceparser/diceparserhelper.h"
+#include "node/executionnode.h"
+#include "validator.h"
+#include <Qt>
+/**
+ * @brief The BooleanCondition class is a Validator class checking validity from logic expression.
+ * It manages many operators (see : @ref LogicOperator).
+ */
+class BooleanCondition : public Validator
+{
+public:
+ BooleanCondition();
+ virtual ~BooleanCondition() override;
+
+ virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override;
+
+ void setOperator(Dice::CompareOperator m);
+ void setValueNode(ExecutionNode*);
+ QString toString() override;
+
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual Validator* getCopy() const override;
+
+private:
+ qint64 valueToScalar() const;
+
+private:
+ Dice::CompareOperator m_operator;
+ ExecutionNode* m_value= nullptr;
+};
+
+// Q_DECLARE_METATYPE(BooleanCondition::LogicOperator)
+#endif // BOOLEANCONDITION_H
diff --git a/src/libparser/compositevalidator.cpp b/src/libparser/compositevalidator.cpp
new file mode 100644
index 0000000..b0f127d
--- /dev/null
+++ b/src/libparser/compositevalidator.cpp
@@ -0,0 +1,196 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "compositevalidator.h"
+
+#include <map>
+
+CompositeValidator::CompositeValidator() {}
+
+CompositeValidator::~CompositeValidator()
+{
+ qDeleteAll(m_validatorList);
+}
+qint64 CompositeValidator::hasValid(Die* b, bool recursive, bool unhighlight) const
+{
+ int i= 0;
+ qint64 sum= 0;
+ bool highLight= false;
+ for(auto& validator : m_validatorList)
+ {
+ qint64 val= validator->hasValid(b, recursive, unhighlight);
+ if(i == 0)
+ {
+ sum= val;
+ if(b->isHighlighted())
+ {
+ highLight= b->isHighlighted();
+ }
+ }
+ else
+ {
+ switch(m_operators.at(i - 1))
+ {
+ case OR:
+ sum|= val;
+
+ if(highLight)
+ {
+ b->setHighlighted(highLight);
+ }
+ break;
+ case EXCLUSIVE_OR:
+ sum^= val; /// @todo may required to be done by hand
+ break;
+ case AND:
+ sum&= val;
+ break;
+ default:
+ break;
+ }
+ }
+ ++i;
+ }
+
+ return sum;
+}
+
+QString CompositeValidator::toString()
+{
+ // m_validatorList
+ QStringList validatorsTextList;
+ std::transform(m_validatorList.begin(), m_validatorList.end(), std::back_inserter(validatorsTextList),
+ [](Validator* validator) { return validator->toString(); });
+ QStringList operatorTextList;
+ std::transform(
+ m_operators.begin(), m_operators.end(), std::back_inserter(operatorTextList), [](LogicOperation validator) {
+ static std::map<LogicOperation, QString> map({{OR, "|"}, {EXCLUSIVE_OR, "^"}, {AND, "&"}, {NONE, ""}});
+ return map[validator];
+ });
+
+ if(validatorsTextList.size() - 1 != operatorTextList.size())
+ return QString("Error - operator and validator count don't fit");
+
+ QStringList result;
+ int i= 0;
+ for(auto text : validatorsTextList)
+ {
+ result << text << operatorTextList[i];
+
+ ++i;
+ }
+ return result.join(" ");
+}
+
+Dice::CONDITION_STATE testAND(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == Dice::CONDITION_STATE::UNREACHABLE || current == Dice::CONDITION_STATE::UNREACHABLE)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(before == Dice::CONDITION_STATE::ALWAYSTRUE && current == Dice::CONDITION_STATE::ALWAYSTRUE)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testOR(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == Dice::CONDITION_STATE::UNREACHABLE && current == Dice::CONDITION_STATE::UNREACHABLE)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(before == Dice::CONDITION_STATE::ALWAYSTRUE || current == Dice::CONDITION_STATE::ALWAYSTRUE)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testXOR(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == current
+ && (before == Dice::CONDITION_STATE::UNREACHABLE || before == Dice::CONDITION_STATE::ALWAYSTRUE))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if((before != current)
+ && (before == Dice::CONDITION_STATE::ALWAYSTRUE || before == Dice::CONDITION_STATE::UNREACHABLE)
+ && (before != Dice::CONDITION_STATE::REACHABLE || current != Dice::CONDITION_STATE::REACHABLE))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE CompositeValidator::isValidRangeSize(const std::pair<qint64, qint64>& range) const
+{
+ std::vector<Dice::CONDITION_STATE> vec;
+ std::transform(
+ m_validatorList.begin(), m_validatorList.end(), std::back_inserter(vec),
+ [range](Validator* validator) -> Dice::CONDITION_STATE { return validator->isValidRangeSize(range); });
+
+ auto itError= std::find(vec.begin(), vec.end(), Dice::CONDITION_STATE::ERROR_STATE);
+
+ if((static_cast<int>(vec.size()) != m_operators.size() + 1) || (itError != vec.end()))
+ {
+ return Dice::CONDITION_STATE::ERROR_STATE;
+ }
+
+ std::size_t i= 0;
+ Dice::CONDITION_STATE val= Dice::CONDITION_STATE::ERROR_STATE;
+ for(const auto& op : m_operators)
+ {
+ auto currentState= vec[i + 1];
+ if(i == 0)
+ {
+ val= vec[i];
+ }
+ switch(op)
+ {
+ case OR:
+ val= testAND(val, currentState);
+ break;
+ case EXCLUSIVE_OR:
+ val= testOR(val, currentState);
+ break;
+ case AND:
+ val= testXOR(val, currentState);
+ break;
+ case NONE:
+ val= Dice::CONDITION_STATE::ERROR_STATE;
+ break;
+ }
+
+ ++i;
+ }
+ return val;
+}
+
+void CompositeValidator::setOperationList(const QVector<LogicOperation>& m)
+{
+ m_operators= m;
+}
+
+void CompositeValidator::setValidatorList(const QList<Validator*>& valids)
+{
+ qDeleteAll(m_validatorList);
+ m_validatorList= valids;
+}
+Validator* CompositeValidator::getCopy() const
+{
+ CompositeValidator* val= new CompositeValidator();
+ val->setOperationList(m_operators);
+ val->setValidatorList(m_validatorList);
+ return val;
+}
diff --git a/src/libparser/compositevalidator.h b/src/libparser/compositevalidator.h
new file mode 100644
index 0000000..c2c066a
--- /dev/null
+++ b/src/libparser/compositevalidator.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef COMPOSITEVALIDATOR_H
+#define COMPOSITEVALIDATOR_H
+
+#include <QList>
+#include <QString>
+#include <QVector>
+#include <Qt>
+
+#include "validator.h"
+/**
+ * @brief The BooleanCondition class is a Validator class checking validity from logic expression.
+ * It manages many operators (see : @ref LogicOperator).
+ */
+class CompositeValidator : public Validator
+{
+public:
+ enum LogicOperation
+ {
+ OR,
+ EXCLUSIVE_OR,
+ AND,
+ NONE
+ };
+ CompositeValidator();
+ virtual ~CompositeValidator() override;
+
+ virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override;
+
+ void setOperationList(const QVector<LogicOperation>& m);
+ void setValidatorList(const QList<Validator*>& valids);
+
+ QString toString() override;
+
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override;
+
+ virtual Validator* getCopy() const override;
+
+private:
+ QVector<LogicOperation> m_operators;
+ QList<Validator*> m_validatorList;
+};
+
+#endif // BOOLEANCONDITION_H
diff --git a/src/libparser/dicealias.cpp b/src/libparser/dicealias.cpp
new file mode 100644
index 0000000..a5c079d
--- /dev/null
+++ b/src/libparser/dicealias.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include <QRegularExpression>
+#include <diceparser/dicealias.h>
+
+#include <QDebug>
+
+QString makeReplament(const QString& pattern, const QString& command, QString cmd)
+{
+ auto hasPattern= cmd.contains(pattern);
+ if(hasPattern)
+ {
+ auto idxPattern= cmd.indexOf(pattern);
+ std::vector<std::pair<int, int>> quotes;
+
+ int pos= 0;
+ bool open= true;
+ while(pos != -1 && pos < cmd.size())
+ {
+ auto oldPos= pos;
+ pos= cmd.indexOf("\"", pos);
+ if(open && pos != -1)
+ open= false;
+ else if(pos != -1)
+ {
+ quotes.push_back({oldPos, pos});
+ }
+
+ if(pos != -1)
+ pos+= 1;
+ }
+ auto hasQuote= false;
+ for(auto range : quotes)
+ {
+ if(idxPattern < range.second && idxPattern >= range.first)
+ hasQuote= true;
+ }
+
+ auto hasVariable= cmd.contains("${");
+ auto commentPos= cmd.lastIndexOf("#");
+
+ if(!hasQuote && !hasVariable)
+ {
+ cmd.replace(pattern, command);
+ }
+ else
+ {
+ std::vector<int> patternPosList;
+ std::vector<std::pair<int, int>> variablePos;
+
+ int pos= 0;
+ QRegularExpressionMatch match;
+ while(pos != -1)
+ {
+ auto start= cmd.indexOf(QRegularExpression("\\${\\N+}"), pos, &match);
+ if(start >= 0)
+ {
+ auto end= start + match.captured().length();
+ variablePos.push_back(std::make_pair(start, end));
+ pos= end + 1;
+ }
+ else
+ {
+ pos= start;
+ }
+ }
+
+ pos= 0;
+ while(pos != -1)
+ {
+ auto start= cmd.indexOf("\"", pos);
+ if(start >= 0)
+ {
+ auto end= cmd.indexOf("\"", start + 1);
+ variablePos.push_back(std::make_pair(start, end));
+ pos= end + 1;
+ }
+ else
+ {
+ pos= start;
+ }
+ }
+ pos= 0;
+ while((pos= cmd.indexOf(pattern, pos)) && pos != -1)
+ {
+ bool isInsidePair= false;
+ for(auto pair : variablePos)
+ {
+ if(!isInsidePair)
+ isInsidePair= (pos > pair.first && pos < pair.second);
+
+ if(commentPos >= 0 && pos > commentPos)
+ isInsidePair= true;
+ }
+ if(!isInsidePair)
+ patternPosList.push_back(pos);
+
+ pos+= 1;
+ }
+
+ // TODO to be replace by C++14 when it is ready
+ for(auto i= patternPosList.rbegin(); i != patternPosList.rend(); ++i)
+ {
+ cmd.replace(*i, 1, command);
+ }
+ }
+ }
+ return cmd;
+}
+
+DiceAlias::DiceAlias(QString pattern, QString command, QString comment, bool isReplace, bool isEnable)
+ : m_pattern(pattern)
+ , m_command(command)
+ , m_comment(comment)
+ , m_type(isReplace ? REPLACE : REGEXP)
+ , m_isEnable(isEnable)
+{
+}
+
+DiceAlias::~DiceAlias()
+{
+ // qDebug() << "destructeur of alias!" << this;
+}
+
+DiceAlias::DiceAlias(const DiceAlias& alias)
+{
+ m_command= alias.command();
+ m_comment= alias.comment();
+ m_pattern= alias.pattern();
+ m_isEnable= alias.isEnable();
+ m_type= alias.isReplace() ? REPLACE : REGEXP;
+}
+
+bool DiceAlias::resolved(QString& str)
+{
+ if(!m_isEnable)
+ return false;
+
+ if((m_type == REPLACE) && (str.contains(m_pattern)))
+ {
+ str= makeReplament(m_pattern, m_command, str);
+ return true;
+ }
+ else if(m_type == REGEXP)
+ {
+ QRegularExpression exp(m_pattern);
+ str.replace(exp, m_command);
+ return true;
+ }
+ return false;
+}
+
+void DiceAlias::setCommand(QString command)
+{
+ m_command= command;
+}
+
+void DiceAlias::setPattern(const QString& pattern)
+{
+ m_pattern= pattern;
+}
+
+void DiceAlias::setType(RESOLUTION_TYPE type)
+{
+ m_type= type;
+}
+QString DiceAlias::command() const
+{
+ return m_command;
+}
+
+QString DiceAlias::pattern() const
+{
+ return m_pattern;
+}
+
+bool DiceAlias::isReplace() const
+{
+ return (m_type == REPLACE) ? true : false;
+}
+
+void DiceAlias::setReplace(bool b)
+{
+ if(b)
+ {
+ m_type= REPLACE;
+ }
+ else
+ {
+ m_type= REGEXP;
+ }
+}
+
+bool DiceAlias::isEnable() const
+{
+ return m_isEnable;
+}
+
+void DiceAlias::setEnable(bool b)
+{
+ m_isEnable= b;
+}
+
+QString DiceAlias::comment() const
+{
+ return m_comment;
+}
+
+void DiceAlias::setComment(const QString& comment)
+{
+ m_comment= comment;
+}
diff --git a/src/libparser/diceparser.cpp b/src/libparser/diceparser.cpp
new file mode 100644
index 0000000..af86acc
--- /dev/null
+++ b/src/libparser/diceparser.cpp
@@ -0,0 +1,271 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include <diceparser/diceparser.h>
+
+#include <QDebug>
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QObject>
+#include <QStringList>
+#include <functional>
+#include <numeric>
+
+#include "booleancondition.h"
+#include "range.h"
+#include "result/stringresult.h"
+#include "validator.h"
+#include <diceparser/dicealias.h>
+#include <diceparser/parsingtoolbox.h>
+
+#define DEFAULT_FACES_NUMBER 10
+
+DiceParser::DiceParser() : m_parsingToolbox(new ParsingToolBox()) {}
+DiceParser::~DiceParser() {}
+
+const QList<DiceAlias*>& DiceParser::constAliases() const
+{
+ return m_parsingToolbox->getAliases();
+}
+
+QList<DiceAlias*>* DiceParser::aliases() const
+{
+ return m_parsingToolbox->aliases();
+}
+
+void DiceParser::cleanAliases()
+{
+ m_parsingToolbox->cleanUpAliases();
+}
+void DiceParser::insertAlias(DiceAlias* dice, int i)
+{
+ m_parsingToolbox->insertAlias(dice, i);
+}
+
+bool DiceParser::parseLine(QString str, bool allowAlias)
+{
+ if(allowAlias)
+ {
+ str= m_parsingToolbox->convertAlias(str);
+ }
+ m_parsingToolbox->clearUp();
+ m_command= str;
+ auto instructions= m_parsingToolbox->readInstructionList(str, true);
+ m_command.remove(m_parsingToolbox->getComment());
+ bool value= !instructions.empty();
+ if(!value)
+ {
+ m_parsingToolbox->addError(Dice::ERROR_CODE::NOTHING_UNDERSTOOD,
+ QObject::tr("Nothing was understood. To roll dice: !1d6 - full documation: "
+ "<a "
+ "href=\"https://github.com/Rolisteam/DiceParser/blob/master/"
+ "HelpMe.md\">https://github.com/"
+ "Rolisteam/DiceParser/blob/master/HelpMe.md</a>"));
+ }
+ else if(value && !str.isEmpty())
+ {
+ auto i= m_command.size() - str.size();
+ m_parsingToolbox->addWarning(
+ Dice::ERROR_CODE::UNEXPECTED_CHARACTER,
+ QObject::tr("Unexpected character at %1 - end of command was ignored \"%2\"").arg(i).arg(str));
+ }
+
+ if(m_parsingToolbox->hasError())
+ value= false;
+
+ return value;
+}
+
+QString DiceParser::convertAlias(const QString& cmd) const
+{
+ return m_parsingToolbox->convertAlias(cmd);
+}
+
+void DiceParser::start()
+{
+ for(auto start : m_parsingToolbox->getStartNodes())
+ {
+ start->run();
+ }
+}
+
+QString DiceParser::diceCommand() const
+{
+ return m_command;
+}
+
+bool DiceParser::hasIntegerResultNotInFirst() const
+{
+ return m_parsingToolbox->hasIntegerResultNotInFirst();
+}
+
+bool DiceParser::hasDiceResult() const
+{
+ return m_parsingToolbox->hasDiceResult();
+}
+bool DiceParser::hasStringResult() const
+{
+ return m_parsingToolbox->hasStringResult();
+}
+
+int DiceParser::startNodeCount() const
+{
+ return static_cast<int>(m_parsingToolbox->getStartNodes().size());
+}
+
+QList<qreal> DiceParser::scalarResultsFromEachInstruction() const
+{
+ return m_parsingToolbox->scalarResultsFromEachInstruction();
+}
+
+QStringList DiceParser::stringResultFromEachInstruction(bool& hasAlias) const
+{
+ return m_parsingToolbox->allFirstResultAsString(hasAlias);
+}
+
+void DiceParser::diceResultFromEachInstruction(QList<ExportedDiceResult>& resultList) const
+{
+ resultList= m_parsingToolbox->diceResultFromEachInstruction();
+}
+
+QString DiceParser::comment() const
+{
+ return m_parsingToolbox->getComment();
+}
+
+void DiceParser::setComment(const QString& comment)
+{
+ m_parsingToolbox->setComment(comment);
+}
+
+QMap<Dice::ERROR_CODE, QString> DiceParser::errorMap() const
+{
+ QMap<Dice::ERROR_CODE, QString> map;
+
+ for(auto start : m_parsingToolbox->getStartNodes())
+ {
+ auto mapTmp= start->getExecutionErrorMap();
+ auto keys= mapTmp.keys();
+ for(auto& key : keys)
+ {
+ map.insert(key, mapTmp[key]);
+ }
+ }
+ return map;
+}
+QString DiceParser::humanReadableError() const
+{
+ auto parsingError= m_parsingToolbox->getErrorList();
+ QString str;
+ std::for_each(parsingError.begin(), parsingError.end(),
+ [&str](const QString& text)
+ {
+ str.append(text);
+ str.append(QStringLiteral("\n"));
+ });
+
+ /// list
+ auto errMap= errorMap();
+ std::for_each(errMap.begin(), errMap.end(),
+ [&str](const QString& text)
+ {
+ str.append(text);
+ str.append(QStringLiteral("\n"));
+ });
+ return str;
+}
+
+QString DiceParser::humanReadableWarning() const
+{
+ auto warningMap= m_parsingToolbox->getWarningList();
+ QMapIterator<Dice::ERROR_CODE, QString> i(warningMap);
+ QString str("");
+ while(i.hasNext())
+ {
+ i.next();
+ str.append(i.value());
+ str.append(QStringLiteral("\n"));
+ }
+ return str;
+}
+
+QString DiceParser::finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize) const
+{
+ return m_parsingToolbox->finalStringResult(colorize);
+}
+
+QString DiceParser::resultAsJSon(std::function<QString(const QString&, const QString&, bool)> colorize,
+ bool removeUnhighligthed) const
+{
+ QJsonObject obj;
+ QJsonArray instructions;
+ for(auto start : m_parsingToolbox->getStartNodes())
+ {
+ QJsonObject inst;
+
+ m_parsingToolbox->addResultInJson(inst, Dice::RESULT_TYPE::SCALAR, "scalar", start, true);
+ m_parsingToolbox->addResultInJson(inst, Dice::RESULT_TYPE::STRING, "string", start, false);
+ m_parsingToolbox->addDiceResultInJson(inst, start, colorize);
+
+ instructions.append(inst);
+ }
+ obj["instructions"]= instructions;
+ obj["comment"]= m_parsingToolbox->getComment();
+ obj["error"]= humanReadableError();
+ obj["scalar"]= m_parsingToolbox->finalScalarResult().first;
+ obj["string"]= m_parsingToolbox->finalStringResult(colorize, removeUnhighligthed);
+ obj["warning"]= humanReadableWarning();
+ obj["command"]= m_command;
+
+ QJsonDocument doc;
+ doc.setObject(obj);
+ return doc.toJson();
+}
+
+void DiceParser::writeDownDotTree(QString filepath)
+{
+ if(m_parsingToolbox->getStartNodes().empty())
+ return;
+
+ QString str(QStringLiteral("digraph ExecutionTree {\n"));
+ for(auto start : m_parsingToolbox->getStartNodes())
+ {
+ start->generateDotTree(str);
+ }
+ str.append(QStringLiteral("}\n"));
+
+ QFile file(filepath);
+ if(file.open(QIODevice::WriteOnly))
+ {
+ QTextStream in(&file);
+ in << str;
+ }
+}
+void DiceParser::setPathToHelp(QString l)
+{
+ m_parsingToolbox->setHelpPath(l);
+}
+void DiceParser::setVariableDictionary(const QHash<QString, QString>& variables)
+{
+ ParsingToolBox::setVariableHash(variables);
+}
diff --git a/src/libparser/diceparser.pc.in b/src/libparser/diceparser.pc.in
new file mode 100644
index 0000000..61b5aea
--- /dev/null
+++ b/src/libparser/diceparser.pc.in
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
+
+Name: @PROJECT_NAME@
+Description: @PROJECT_DESCRIPTION@
+Version: @PROJECT_VERSION@
+
+Requires:
+Libs: -L${libdir} -ldiceparser
+Cflags: -I${includedir}
diff --git a/src/libparser/diceroller.cpp b/src/libparser/diceroller.cpp
new file mode 100644
index 0000000..e1c8ded
--- /dev/null
+++ b/src/libparser/diceroller.cpp
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * Rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include <diceparser_qobject/diceroller.h>
+
+#include <QJsonObject>
+#include <QtConcurrent>
+
+DiceRoller::DiceRoller(QObject* parent) : QObject(parent) {}
+
+QString DiceRoller::diceList() const
+{
+ return m_diceList;
+}
+
+QString DiceRoller::resultStr() const
+{
+ return m_resultStr;
+}
+
+QString DiceRoller::command() const
+{
+ return m_command;
+}
+
+qreal DiceRoller::result() const
+{
+ return m_result;
+}
+
+void DiceRoller::setCommand(const QString& cmd)
+{
+ if(m_command != cmd)
+ {
+ m_command= cmd;
+ emit commandChanged();
+ }
+}
+
+void DiceRoller::readErrorAndWarning()
+{
+ setError(
+ tr("Error:\n%1\nWarnings:\n%2").arg(m_diceparser.humanReadableError(), m_diceparser.humanReadableWarning()));
+}
+
+void DiceRoller::start()
+{
+ auto future= QtConcurrent::run(
+ [this]()
+ {
+ if(m_diceparser.parseLine(m_command))
+ {
+ m_diceparser.start();
+ readErrorAndWarning();
+ auto jsonstr
+ = m_diceparser.resultAsJSon([](const QString& value, const QString&, bool) { return value; });
+ QJsonDocument doc= QJsonDocument::fromJson(jsonstr.toLocal8Bit());
+ auto json= doc.object();
+ m_result= json["scalar"].toString().toDouble();
+ emit resultChanged();
+ }
+ });
+}
+
+QString DiceRoller::error() const
+{
+ return m_error;
+}
+
+QList<DiceAlias*>* DiceRoller::aliases() const
+{
+ return m_diceparser.aliases();
+}
+
+DiceParser* DiceRoller::parser()
+{
+ return &m_diceparser;
+}
+
+void DiceRoller::setError(const QString& error)
+{
+ if(m_error == error)
+ return;
+
+ m_error= error;
+ emit errorOccurs();
+}
+
+/*QString DiceRoller::diceToText(QList<ExportedDiceResult>& diceList)
+{
+ QStringList global;
+ for(auto& dice : diceList)
+ {
+ QStringList resultGlobal;
+ auto const& keys= dice.keys();
+ for(auto& face : keys)
+ {
+ QStringList result;
+ auto list= dice.value(face);
+ for(auto diceResult : list)
+ {
+ for(const HighLightDice& tmp : diceResult)
+ {
+ QStringList diceListStr;
+ QStringList diceListChildren;
+ int i= 0;
+ for(qint64& dievalue : tmp.result())
+ {
+ QString prefix("%1");
+ if(i == 0)
+ {
+ diceListStr << prefix.arg(QString::number(dievalue));
+ }
+ else
+ {
+ diceListChildren << prefix.arg(QString::number(dievalue));
+ }
+ ++i;
+ }
+ if(!diceListChildren.isEmpty())
+ {
+ diceListStr << QString("[%1]").arg(diceListChildren.join(' '));
+ }
+ result << diceListStr.join(' ');
+ }
+
+if(keys.size() > 1)
+{
+ resultGlobal << QString(" d%2:(%1)").arg(result.join(',')).arg(face);
+}
+else
+{
+ resultGlobal << result;
+}
+}
+}
+global << resultGlobal.join(' ');
+}
+return global.join(" ; ");
+}*/
+
+/*if(m_diceparser.parseLine(m_command))
+ {
+ m_diceparser.start();
+ if(m_diceparser.errorMap().isEmpty())
+ {
+ bool homogeneous;
+ QList<ExportedDiceResult> list;
+ m_diceparser.lastDiceResult(list, homogeneous);
+ QString diceText= diceToText(list);
+ QString scalarText;
+ QString str;
+
+qreal result= 0;
+QString resultStr;
+if(m_diceparser.hasIntegerResultNotInFirst())
+{
+ auto values= m_diceparser.lastIntegerResults();
+ QStringList strLst;
+ for(auto& val : values)
+ {
+ result+= val;
+ strLst << QString::number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+}
+else if(!list.isEmpty())
+{
+ auto values= m_diceparser.getSumOfDiceResult();
+ QStringList strLst;
+ for(auto val : values)
+ {
+ result+= val;
+ strLst << QString::number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+}
+
+if(m_diceparser.hasStringResult())
+{
+ bool ok;
+ QStringList allStringlist= m_diceparser.getAllStringResult(ok);
+ QString stringResult= allStringlist.join(" ; ");
+ stringResult.replace("%1", scalarText);
+ stringResult.replace("%2", diceText.trimmed());
+ str= stringResult;
+}
+else
+{
+ resultStr= scalarText;
+}
+if(!m_diceparser.getComment().isEmpty())
+{
+ resultStr+= m_diceparser.getComment() + "\n";
+}
+resultStr+= str + "\n";
+m_resultStr= resultStr;
+m_result= result;
+m_diceList= diceText.trimmed();
+emit resultStrChanged();
+emit resultChanged();
+emit diceListChanged();
+}
+}
+
+if(!m_diceparser.getErrorMap().isEmpty())
+{
+ auto errors= m_diceparser.getErrorMap();
+ setError(errors.first());
+}
+*/
diff --git a/src/libparser/die.cpp b/src/libparser/die.cpp
new file mode 100644
index 0000000..4214b97
--- /dev/null
+++ b/src/libparser/die.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "die.h"
+
+#include <QDateTime>
+#include <QDebug>
+#include <QUuid>
+#include <algorithm>
+#include <array>
+#include <chrono>
+
+void Die::buildSeed()
+{
+ static bool init= false;
+ if(init)
+ return;
+ std::array<int, std::mt19937::state_size> seed_data;
+ std::random_device r;
+ std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
+ std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
+ s_rng= std::mt19937(seq);
+ init= true;
+}
+
+std::mt19937 Die::s_rng;
+
+Die::Die()
+ : m_uuid(QUuid::createUuid().toString(QUuid::WithoutBraces))
+ , m_hasValue(false)
+ , m_displayStatus(false)
+ , m_highlighted(true)
+ , m_base(1)
+ , m_color("")
+ , m_op(Dice::ArithmeticOperator::PLUS) //,m_mt(m_randomDevice)
+{
+ buildSeed();
+}
+
+Die::Die(const Die& die)
+{
+ m_value= die.m_value;
+ m_rollResult= die.m_rollResult;
+ m_selected= die.m_selected;
+ m_hasValue= die.m_hasValue;
+ m_uuid= die.m_uuid;
+ m_displayStatus= die.m_displayStatus;
+ m_maxValue= die.m_maxValue;
+ m_highlighted= die.m_highlighted;
+ m_base= die.m_base;
+ m_color= die.getColor();
+ m_op= die.getOp();
+ // auto seed= std::chrono::high_resolution_clock::now().time_since_epoch().count();
+ // m_rng= std::mt19937(quintptr(this) + static_cast<unsigned long long>(seed));
+}
+
+void Die::setValue(qint64 r)
+{
+ m_value= r;
+ m_hasValue= true;
+}
+
+void Die::insertRollValue(qint64 r)
+{
+ m_rollResult.append(r);
+}
+
+void Die::setSelected(bool b)
+{
+ m_selected= b;
+}
+
+bool Die::isSelected() const
+{
+ return m_selected;
+}
+qint64 Die::getValue() const
+{
+ if(m_hasValue)
+ {
+ return m_value;
+ }
+ else
+ {
+ qint64 value= 0;
+ int i= 0;
+ for(qint64 tmp : m_rollResult)
+ {
+ if(i > 0)
+ {
+ switch(m_op)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ value+= tmp;
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ value*= tmp;
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ value-= tmp;
+ break;
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ case Dice::ArithmeticOperator::DIVIDE:
+ if(tmp != 0)
+ {
+ value/= tmp;
+ }
+ else
+ {
+ // error();
+ }
+ break;
+ case Dice::ArithmeticOperator::POW:
+ value= static_cast<qint64>(std::pow(value, tmp));
+ break;
+ }
+ }
+ else
+ {
+ value= tmp;
+ }
+ ++i;
+ }
+ return value;
+ }
+}
+QList<qint64> Die::getListValue() const
+{
+ return m_rollResult;
+}
+bool Die::hasChildrenValue()
+{
+ return m_rollResult.size() > 1 ? true : false;
+}
+void Die::replaceLastValue(qint64 value)
+{
+ m_rollResult.removeLast();
+ insertRollValue(value);
+}
+
+void Die::roll(bool adding)
+{
+ if(m_maxValue != 0)
+ {
+ // quint64 value=(qrand()%m_faces)+m_base;
+ std::uniform_int_distribution<qint64> dist(m_base, m_maxValue);
+ qint64 value= dist(s_rng);
+ if((adding) || (m_rollResult.isEmpty()))
+ {
+ insertRollValue(value);
+ }
+ else
+ {
+ replaceLastValue(value);
+ }
+ }
+}
+
+quint64 Die::getFaces() const
+{
+ return std::abs(m_maxValue - m_base) + 1;
+}
+qint64 Die::getLastRolledValue()
+{
+ if(!m_rollResult.isEmpty())
+ {
+ return m_rollResult.last();
+ }
+ else
+ return 0;
+}
+bool Die::hasBeenDisplayed() const
+{
+ return m_displayStatus;
+}
+void Die::displayed()
+{
+ setDisplayed(true);
+}
+void Die::setDisplayed(bool b)
+{
+ m_displayStatus= b;
+}
+void Die::setHighlighted(bool a)
+{
+ m_highlighted= a;
+}
+
+bool Die::isHighlighted() const
+{
+ return m_highlighted;
+}
+void Die::setBase(qint64 base)
+{
+ m_base= base;
+}
+qint64 Die::getBase()
+{
+ return m_base;
+}
+QString Die::getColor() const
+{
+ return m_color;
+}
+
+void Die::setColor(const QString& color)
+{
+ m_color= color;
+}
+
+qint64 Die::getMaxValue() const
+{
+ return m_maxValue;
+}
+
+void Die::setMaxValue(const qint64& maxValue)
+{
+ m_maxValue= maxValue;
+}
+
+Dice::ArithmeticOperator Die::getOp() const
+{
+ return m_op;
+}
+
+void Die::setOp(const Dice::ArithmeticOperator& op)
+{
+ m_op= op;
+}
+QString Die::getUuid() const
+{
+ return m_uuid;
+}
+
+void Die::setUuid(const QString& uuid)
+{
+ m_uuid= uuid;
+}
diff --git a/src/libparser/die.h b/src/libparser/die.h
new file mode 100644
index 0000000..2da2006
--- /dev/null
+++ b/src/libparser/die.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef DIE_H
+#define DIE_H
+
+#include <QList>
+#include <QString>
+#include <random>
+
+#include "diceparser/diceparserhelper.h"
+/**
+ * @brief The Die class implements all methods required from a die. You must set the Faces first, then you can roll it
+ * and roll it again, to add or replace the previous result.
+ */
+class Die
+{
+public:
+ /**
+ * @brief Die
+ */
+ Die();
+ /**
+ * @brief Die
+ */
+ Die(const Die&);
+ /**
+ * @brief setValue
+ * @param r
+ */
+ void setValue(qint64 r);
+ /**
+ * @brief insertRollValue
+ * @param r
+ */
+ void insertRollValue(qint64 r);
+ /**
+ * @brief setSelected
+ * @param b
+ */
+ void setSelected(bool b);
+ /**
+ * @brief isSelected
+ * @return
+ */
+ bool isSelected() const;
+ /**
+ * @brief getValue
+ * @return
+ */
+ qint64 getValue() const;
+ /**
+ * @brief getListValue
+ * @return
+ */
+ QList<qint64> getListValue() const;
+ /**
+ * @brief hasChildrenValue
+ * @return
+ */
+ bool hasChildrenValue();
+
+ /**
+ * @brief roll
+ * @param adding
+ */
+ void roll(bool adding= false);
+ /**
+ * @brief replaceLastValue
+ * @param value
+ */
+ void replaceLastValue(qint64 value);
+
+ /**
+ * @brief getLastRolledValue
+ * @return
+ */
+ qint64 getLastRolledValue();
+ /**
+ * @brief getFaces
+ * @return
+ */
+ quint64 getFaces() const;
+ /**
+ * @brief hasBeenDisplayed
+ * @return
+ */
+ bool hasBeenDisplayed() const;
+ /**
+ * @brief displayed
+ */
+ void displayed();
+ /**
+ * @brief setHighlighted
+ */
+ void setHighlighted(bool);
+ /**
+ * @brief isHighlighted
+ * @return
+ */
+ bool isHighlighted() const;
+
+ /**
+ * @brief setBase
+ */
+ void setBase(qint64);
+ qint64 getBase();
+
+ QString getColor() const;
+ void setColor(const QString& color);
+
+ qint64 getMaxValue() const;
+ void setMaxValue(const qint64& maxValue);
+
+ Dice::ArithmeticOperator getOp() const;
+ void setOp(const Dice::ArithmeticOperator& op);
+ void setDisplayed(bool b);
+
+ QString getUuid() const;
+ void setUuid(const QString& uuid);
+
+ static void buildSeed();
+
+private:
+ QString m_uuid;
+ qint64 m_value{0};
+ QList<qint64> m_rollResult;
+ bool m_selected{false};
+ bool m_hasValue{false};
+ bool m_displayStatus{false};
+ bool m_highlighted{true};
+ qint64 m_maxValue{0};
+ qint64 m_base{0};
+ qint64 m_occurence{1};
+ QString m_color;
+
+ Dice::ArithmeticOperator m_op;
+
+ static std::mt19937 s_rng;
+};
+
+#endif // DIE_H
diff --git a/src/libparser/highlightdice.cpp b/src/libparser/highlightdice.cpp
new file mode 100644
index 0000000..e92451f
--- /dev/null
+++ b/src/libparser/highlightdice.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include <diceparser/highlightdice.h>
+
+HighLightDice::HighLightDice(QList<qint64> result, bool isHighlighted, QString color, bool displayed, quint64 faces,
+ const QString& uuid)
+ : m_result(result)
+ , m_hasHighlight(isHighlighted)
+ , m_color(color)
+ , m_displayed(displayed)
+ , m_faces(faces)
+ , m_uuid(uuid)
+{
+}
+
+HighLightDice::~HighLightDice() {}
+
+QList<qint64> HighLightDice::result() const
+{
+ return m_result;
+}
+
+void HighLightDice::setResult(const QList<qint64>& result)
+{
+ m_result= result;
+}
+
+bool HighLightDice::isHighlighted() const
+{
+ return m_hasHighlight;
+}
+
+void HighLightDice::setHighlight(bool hasHighlight)
+{
+ m_hasHighlight= hasHighlight;
+}
+
+QString HighLightDice::color() const
+{
+ return m_color;
+}
+
+void HighLightDice::setColor(const QString& color)
+{
+ m_color= color;
+}
+
+bool HighLightDice::displayed() const
+{
+ return m_displayed;
+}
+
+void HighLightDice::setDisplayed(bool displayed)
+{
+ m_displayed= displayed;
+}
+
+quint64 HighLightDice::faces() const
+{
+ return m_faces;
+}
+
+void HighLightDice::setFaces(const quint64& faces)
+{
+ m_faces= faces;
+}
+
+QString HighLightDice::getResultString() const
+{
+ if(m_result.size() == 1)
+ {
+ return QString::number(m_result.first());
+ }
+ else
+ {
+ QStringList list;
+ std::transform(std::begin(m_result), std::end(m_result), std::back_inserter(list),
+ [](qint64 value) { return QString::number(value); });
+
+ auto totalScore= std::accumulate(std::begin(m_result), std::end(m_result), 0);
+ return QStringLiteral("%2 [%1]").arg(list.join(",")).arg(totalScore);
+ }
+}
+
+QString HighLightDice::uuid() const
+{
+ return m_uuid;
+}
+
+void HighLightDice::setUuid(const QString& uuid)
+{
+ m_uuid= uuid;
+}
diff --git a/src/libparser/include/diceparser/dicealias.h b/src/libparser/include/diceparser/dicealias.h
new file mode 100644
index 0000000..05d5a0b
--- /dev/null
+++ b/src/libparser/include/diceparser/dicealias.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef DICEALIAS_H
+#define DICEALIAS_H
+
+#include <QString>
+
+#include <diceparser/diceparser_global.h>
+/**
+ * @brief The DiceAlias class is dedicated to store aliases, alias is mainly two QString. The Alias and its replacement.
+ * The replacement can be a simple QString or a RegExp.
+ */
+class DICEPARSER_EXPORT DiceAlias
+{
+public:
+ enum RESOLUTION_TYPE
+ {
+ REPLACE,
+ REGEXP
+ };
+ /**
+ * @brief DiceAlias
+ * @param cmd
+ * @param key
+ * @param isReplace
+ */
+ DiceAlias(QString pattern, QString command, QString comment= QString{}, bool isReplace= true, bool isEnable= true);
+ DiceAlias(const DiceAlias& alias);
+ /**
+ * @brief ~DiceAlias
+ */
+ virtual ~DiceAlias();
+ /**
+ * @brief resolved
+ * @param str
+ * @return
+ */
+ bool resolved(QString& str);
+ /**
+ * @brief setCommand
+ * @param key
+ */
+ void setPattern(const QString& pattern);
+ /**
+ * @brief setValue
+ * @param value
+ */
+ void setCommand(QString command);
+ /**
+ * @brief setType
+ */
+ void setType(RESOLUTION_TYPE);
+
+ /**
+ * @brief getCommand
+ * @return
+ */
+ QString pattern() const;
+ /**
+ * @brief getValue
+ * @return
+ */
+ QString command() const;
+ /**
+ * @brief isReplace
+ * @return
+ */
+ bool isReplace() const;
+ /**
+ * @brief setReplace
+ */
+ void setReplace(bool);
+
+ /**
+ * @brief isEnable
+ * @return
+ */
+ bool isEnable() const;
+ /**
+ * @brief setEnable
+ * @param b
+ */
+ void setEnable(bool b);
+ /**
+ * @brief getComment
+ * @return
+ */
+ QString comment() const;
+ /**
+ * @brief setComment
+ * @param comment
+ */
+ void setComment(const QString& comment);
+
+private:
+ QString m_pattern;
+ QString m_command;
+ QString m_comment;
+ RESOLUTION_TYPE m_type;
+ bool m_isEnable;
+};
+
+#endif // DICEALIAS_H
diff --git a/src/libparser/include/diceparser/diceparser.h b/src/libparser/include/diceparser/diceparser.h
new file mode 100644
index 0000000..bf2d570
--- /dev/null
+++ b/src/libparser/include/diceparser/diceparser.h
@@ -0,0 +1,130 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef DICEPARSER_H
+#define DICEPARSER_H
+
+#include <QJsonObject>
+#include <QMap>
+#include <QString>
+#include <QVariant>
+#include <memory>
+#include <vector>
+
+#include <diceparser/diceparser_global.h>
+
+#include <diceparser/diceparserhelper.h>
+#include <diceparser/highlightdice.h>
+
+class ExplodeDiceNode;
+class ParsingToolBox;
+class DiceRollerNode;
+class DiceAlias;
+class ExecutionNode;
+/**
+ * @page DiceParser Dice Parser
+ *
+ * @section Intro Introduction
+ * Diceparser is the software component dedicated to compute dice command in rolisteam.<br/>
+ *
+ * @section grammar The Grammar
+ *
+ * The grammar is described in Readme.md
+ */
+
+/**
+ * @brief The DiceParser class facade class, it receives a command and return a DiceResult class (not yet implemented).
+ */
+class DICEPARSER_EXPORT DiceParser
+{
+public:
+ /**
+ * @brief DiceParser default constructor
+ */
+ DiceParser();
+ /**
+ * @brief ~DiceParser
+ */
+ virtual ~DiceParser();
+
+ // Command process methods
+ /**
+ * @brief parseLine, method to call for starting the dice roll. It will parse the command and run the execution
+ * tree.
+ * @param str dice command
+ * @return bool every thing is fine or not
+ */
+ bool parseLine(QString str, bool allowAlias= true);
+ void start();
+ void cleanAll();
+
+ // debug
+ void writeDownDotTree(QString filepath);
+
+ // control methods
+ bool hasIntegerResultNotInFirst() const;
+ bool hasDiceResult() const;
+ bool hasStringResult() const;
+ bool hasSeparator() const;
+
+ // alias management
+ const QList<DiceAlias*>& constAliases() const;
+ QList<DiceAlias*>* aliases() const;
+ void cleanAliases();
+ void insertAlias(DiceAlias*, int);
+ QString convertAlias(const QString& cmd) const;
+
+ QStringList allFirstResultAsString(bool& hasAlias);
+ QStringList getAllDiceResult(bool& hasAlias);
+
+ // Accessors
+ int startNodeCount() const;
+ QList<qreal> scalarResultsFromEachInstruction() const;
+ QStringList stringResultFromEachInstruction(bool& hasAlias) const;
+ void diceResultFromEachInstruction(QList<ExportedDiceResult>& resultList) const;
+ QString finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize) const;
+
+ QString diceCommand() const;
+ QMap<Dice::ERROR_CODE, QString> errorMap() const;
+ QString comment() const;
+ QString humanReadableWarning() const;
+ QString humanReadableError() const;
+ QString resultAsJSon(std::function<QString(const QString&, const QString&, bool)> colorize,
+ bool removeUnhighligthed= false) const;
+
+ // QStringList stringResult() const;
+ // QStringList allDiceResult(bool& hasAlias) const;
+ // void lastDiceResult(QList<ExportedDiceResult>& diceValues, bool& homogeneous) const;
+
+ // setters
+ void setPathToHelp(QString l);
+ void setVariableDictionary(const QHash<QString, QString>& variables);
+ void setComment(const QString& comment);
+
+private:
+ bool readBlocInstruction(QString& str, ExecutionNode*& resultnode);
+
+private:
+ std::unique_ptr<ParsingToolBox> m_parsingToolbox;
+ QString m_command;
+};
+
+#endif // DICEPARSER_H
diff --git a/src/libparser/include/diceparser/diceparser_global.h b/src/libparser/include/diceparser/diceparser_global.h
new file mode 100644
index 0000000..47829cc
--- /dev/null
+++ b/src/libparser/include/diceparser/diceparser_global.h
@@ -0,0 +1,11 @@
+#ifndef DICEPARSER_GLOBAL_H
+#define DICEPARSER_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(DICEPARSER_LIBRARY)
+#define DICEPARSER_EXPORT Q_DECL_EXPORT
+#else
+#define DICEPARSER_EXPORT Q_DECL_IMPORT
+#endif
+#endif // DICEPARSER_GLOBAL_H
diff --git a/src/libparser/include/diceparser/diceparserhelper.h b/src/libparser/include/diceparser/diceparserhelper.h
new file mode 100644
index 0000000..6190df2
--- /dev/null
+++ b/src/libparser/include/diceparser/diceparserhelper.h
@@ -0,0 +1,96 @@
+#ifndef DICEPARSERHELPER_H
+#define DICEPARSERHELPER_H
+
+class ValidatorList;
+class ExecutionNode;
+
+#include <diceparser/diceparser_global.h>
+
+namespace Dice
+{
+enum class CONDITION_STATE : int
+{
+ ERROR_STATE,
+ ALWAYSTRUE,
+ UNREACHABLE,
+ REACHABLE
+};
+
+enum class ERROR_CODE : int
+{
+ NO_DICE_ERROR,
+ DIE_RESULT_EXPECTED,
+ BAD_SYNTAXE,
+ ENDLESS_LOOP_ERROR,
+ DIVIDE_BY_ZERO,
+ NOTHING_UNDERSTOOD,
+ NO_DICE_TO_ROLL,
+ TOO_MANY_DICE,
+ NO_VARIBALE,
+ INVALID_INDEX,
+ UNEXPECTED_CHARACTER,
+ NO_PREVIOUS_ERROR,
+ NO_VALID_RESULT,
+ SCALAR_RESULT_EXPECTED
+};
+
+/**
+ * @brief The RESULT_TYPE enum or combinaison
+ */
+enum class RESULT_TYPE : int
+{
+ NONE= 0,
+ SCALAR= 1,
+ STRING= 2,
+ DICE_LIST= 4
+};
+/**
+ * @brief The ConditionType enum defines compare method
+ */
+enum ConditionType
+{
+ OnEach,
+ OnEachValue,
+ OneOfThem,
+ AllOfThem,
+ OnScalar
+};
+
+enum class CompareOperator
+{
+ Equal,
+ GreaterThan,
+ LesserThan,
+ GreaterOrEqual,
+ LesserOrEqual,
+ Different
+};
+enum class ArithmeticOperator
+{
+ PLUS,
+ MINUS,
+ DIVIDE,
+ MULTIPLICATION,
+ INTEGER_DIVIDE,
+ POW
+};
+enum class LogicOperation
+{
+ OR,
+ EXCLUSIVE_OR,
+ AND,
+ NONE
+};
+
+enum class ConditionOperator
+{
+ Modulo
+};
+
+struct DICEPARSER_EXPORT CaseInfo
+{
+ ValidatorList* validatorList;
+ ExecutionNode* node;
+};
+} // namespace Dice
+#endif // DICEPARSERHELPER_H
diff --git a/src/libparser/include/diceparser/highlightdice.h b/src/libparser/include/diceparser/highlightdice.h
new file mode 100644
index 0000000..a3928a1
--- /dev/null
+++ b/src/libparser/include/diceparser/highlightdice.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef HighLightDice_H
+#define HighLightDice_H
+
+#include <QList>
+#include <QMap>
+#include <QString>
+
+#include <diceparser/diceparser_global.h>
+
+class DICEPARSER_EXPORT HighLightDice
+{
+public:
+ HighLightDice(QList<qint64> result, bool isHighlighted, QString color, bool displayed, quint64 faces,
+ const QString& uuid);
+ virtual ~HighLightDice();
+
+ QList<qint64> result() const;
+ void setResult(const QList<qint64>& result);
+
+ bool isHighlighted() const;
+ void setHighlight(bool hasHighlight);
+
+ QString color() const;
+ void setColor(const QString& color);
+
+ bool displayed() const;
+ void setDisplayed(bool displayed);
+
+ quint64 faces() const;
+ void setFaces(const quint64& faces);
+
+ QString getResultString() const;
+
+ QString uuid() const;
+ void setUuid(const QString& uuid);
+
+private:
+ QList<qint64> m_result;
+ bool m_hasHighlight= true;
+ QString m_color;
+ bool m_displayed= false;
+ quint64 m_faces;
+ QString m_uuid;
+};
+
+typedef QList<HighLightDice> ListDiceResult;
+typedef QMap<quint64, QList<ListDiceResult>> ExportedDiceResult;
+
+#endif // HighLightDice_H
diff --git a/src/libparser/include/diceparser/parsingtoolbox.h b/src/libparser/include/diceparser/parsingtoolbox.h
new file mode 100644
index 0000000..69f433a
--- /dev/null
+++ b/src/libparser/include/diceparser/parsingtoolbox.h
@@ -0,0 +1,284 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PARSINGTOOLBOX_H
+#define PARSINGTOOLBOX_H
+
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QMap>
+#include <QVariant>
+#include <functional>
+#include <vector>
+
+#include "diceparserhelper.h"
+#include "highlightdice.h"
+//#include "dicerollernode.h"
+//#include "executionnode.h"
+//#include "node/ifnode.h"
+//#include "node/paintnode.h"
+//#include "node/scalaroperatornode.h"
+//#include "operationcondition.h"
+//#include "range.h"
+//#include "validatorlist.h"
+
+#include <diceparser/diceparser_global.h>
+class Range;
+class RepeaterNode;
+class DiceAlias;
+class ExplodeDiceNode;
+class SwitchCaseNode;
+class ReplaceValueNode;
+class PainterNode;
+class ValidatorList;
+class Validator;
+class DiceRollerNode;
+class ExecutionNode;
+class DICEPARSER_EXPORT SubtituteInfo
+{
+public:
+ SubtituteInfo();
+
+ bool isValid() const;
+
+ int length() const;
+ void setLength(int length);
+
+ int resultIndex() const;
+ void setResultIndex(int valueIndex);
+
+ int position() const;
+ void setPosition(int position);
+
+ int digitNumber() const;
+ void setDigitNumber(int digitNumber);
+
+ int subIndex() const;
+ void setSubIndex(int subindex);
+
+private:
+ int m_length= 2;
+ int m_digitNumber= 0;
+ int m_resultIndex= -1;
+ int m_position= -1;
+ int m_subIndex= -1;
+};
+
+/**
+ * @brief The ParsingToolBox is gathering many useful methods for dice parsing.
+ * Its goal is to make the diceparser a bit lighter.
+ */
+class DICEPARSER_EXPORT ParsingToolBox
+{
+public:
+ enum LIST_OPERATOR
+ {
+ NONE= 0x00,
+ UNIQUE= 0x01,
+ NOCOMMA= 0x02,
+ UniqueAndNoComma= 0x03
+ };
+
+ enum Function
+ {
+ REPEAT
+ };
+ enum OptionOperator
+ {
+ KeepAndExplode, // K
+ Keep, // k
+ Reroll, // r
+ RerollUntil, // R
+ Explode, // e
+ Sort, // s
+ Count, // c
+ RerollAndAdd, // a
+ Merge, // m
+ ifOperator, // i
+ Painter, // p
+ Filter, // f
+ Split, // y
+ Group, // g
+ Occurences, // o
+ Unique, // u
+ Bind, // b
+ AllSameExplode, // t
+ SwitchCaseOption, // S
+ TransformOption // T
+ };
+ enum DiceOperator
+ {
+ D,
+ L
+ };
+ enum NodeAction
+ {
+ JumpBackward
+ };
+ ParsingToolBox();
+ ParsingToolBox(const ParsingToolBox& data);
+ virtual ~ParsingToolBox();
+ void clearUp();
+
+ // Build execution tree
+ DiceRollerNode* getDiceRollerNode(ExecutionNode* previous);
+ DiceRollerNode* addRollDiceNode(qint64 faces, ExecutionNode*);
+ ExplodeDiceNode* addExplodeDiceNode(qint64 faces, ExecutionNode* previous);
+ Dice::CONDITION_STATE isValidValidator(ExecutionNode* previous, ValidatorList* val);
+ ExecutionNode* addSort(ExecutionNode* e, bool b);
+
+ // parsing tools
+ static bool readAscending(QString& str);
+ static bool readStopAtFirst(QString& str);
+ bool readLogicOperator(QString& str, Dice::CompareOperator& op);
+ Validator* readValidator(QString& str, bool hasSquare= false);
+ ValidatorList* readValidatorList(QString& str);
+ static bool readNumber(QString& str, qint64& myNumber);
+ static bool readString(QString& str, QString& strresult);
+ static bool readVariable(QString& str, qint64& myNumber, QString& reasonFail);
+ static bool readOpenParentheses(QString& str);
+ static bool readCloseParentheses(QString& str);
+
+ static bool readDynamicVariable(QString& str, qint64& index);
+ bool readList(QString& str, QStringList& list, QList<Range>& ranges);
+ bool readDiceRange(QString& str, qint64& start, qint64& end);
+ static LIST_OPERATOR readListOperator(QString& str);
+ void readProbability(QStringList& str, QList<Range>& ranges);
+ bool readLogicOperation(QString& str, Dice::LogicOperation& op);
+ bool readDiceLogicOperator(QString& str, Dice::ConditionOperator& op);
+ bool readArithmeticOperator(QString& str, Dice::ArithmeticOperator& op);
+ std::vector<ExecutionNode*> readInstructionList(QString& str, bool startNode);
+ static Dice::ConditionType readConditionType(QString& str);
+ bool readComment(QString& str, QString&, QString&);
+ bool readOperand(QString& str, ExecutionNode*& node);
+ static int findClosingCharacterIndexOf(QChar open, QChar closing, const QString& str, int offset);
+ static void readSubtitutionParameters(SubtituteInfo& info, QString& rest);
+ static bool readPainterParameter(PainterNode* painter, QString& str);
+ static bool readComma(QString& str);
+ bool readReaperArguments(RepeaterNode* node, QString& source);
+ bool readExpression(QString& str, ExecutionNode*& node);
+ bool readInstructionOperator(QChar c);
+ bool readNode(QString& str, ExecutionNode*& node);
+ /**
+ * @brief readIfInstruction reads the current command to build if node with proper parameters.
+ * @param str is the command string, if IF istruction is found, the str will be changed, in other case the string is
+ * unmodified
+ * @param trueNode is the branch's beginning to be executed if the IfNode is true.
+ * @param falseNode is the branch's beginning to be executed if the IfNode is false.
+ * @return true, ifNode has been found, false otherwise
+ */
+ bool readIfInstruction(QString& str, ExecutionNode*& trueNode, ExecutionNode*& falseNode);
+ bool readOptionFromNull(QString& str, ExecutionNode*& node);
+ bool readOperatorFromNull(QString& str, ExecutionNode*& node);
+ bool readParameterNode(QString& str, ExecutionNode*& node);
+ bool readFunction(QString& str, ExecutionNode*& node);
+ bool readDice(QString& str, ExecutionNode*& node);
+ bool readDiceOperator(QString&, DiceOperator&);
+ bool readDiceExpression(QString&, ExecutionNode*& node);
+ bool readOperator(QString&, ExecutionNode* previous);
+ bool readCommand(QString& str, ExecutionNode*& node);
+ bool readBlocInstruction(QString& str, ExecutionNode*& resultnode);
+ bool readOption(QString&, ExecutionNode* node); // OptionOperator& option,
+ bool readValuesList(QString& str, ExecutionNode*& node);
+ bool readSwitchCaseNode(QString& str, SwitchCaseNode* node);
+ bool readReplaceValueNode(QString& str, ReplaceValueNode* node);
+
+ // Error
+ bool hasError() const;
+ void addError(Dice::ERROR_CODE code, const QString& msg);
+ void addWarning(Dice::ERROR_CODE code, const QString& msg);
+ const QMap<Dice::ERROR_CODE, QString>& getErrorList() const;
+ const QMap<Dice::ERROR_CODE, QString>& getWarningList() const;
+
+ // Traversal functions
+ static QString number(qreal value);
+ static ExecutionNode* getLeafNode(ExecutionNode* start);
+ const std::vector<ExecutionNode*>& getStartNodes();
+ static void setStartNodes(std::vector<ExecutionNode*>* startNodes);
+ std::pair<bool, QVariant> hasResultOfType(Dice::RESULT_TYPE, ExecutionNode* node, bool notthelast= false) const;
+ QList<qreal> scalarResultsFromEachInstruction() const;
+ std::pair<QString, QString> finalScalarResult() const;
+ QString finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize,
+ bool removeUnhighlighted= false) const;
+ QStringList allFirstResultAsString(bool& hasAlias) const;
+ QList<qreal> sumOfDiceResult() const;
+ QList<ExportedDiceResult> diceResultFromEachInstruction() const;
+ bool hasIntegerResultNotInFirst() const;
+ bool hasDiceResult() const;
+ bool hasStringResult() const;
+
+ // result
+ static QString replaceVariableToValue(const QString& source, QStringList values,
+ QMap<Dice::ERROR_CODE, QString>& errorMap);
+ static QString replacePlaceHolderToValue(const QString& source, const QList<ExportedDiceResult>& list,
+ bool removeUnhighlighted,
+ std::function<QString(const QString&, const QString&, bool)> colorize);
+ static SubtituteInfo readVariableFromString(const QString& source, int& start);
+ static SubtituteInfo readPlaceHolderFromString(const QString& source, int& start);
+ static ExportedDiceResult finalDiceResultFromInstruction(ExecutionNode* start);
+ static ExportedDiceResult allDiceResultFromInstruction(ExecutionNode* start);
+ void addResultInJson(QJsonObject& obj, Dice::RESULT_TYPE type, const QString& key, ExecutionNode* start, bool b);
+ void addDiceResultInJson(QJsonObject& obj, ExecutionNode* start,
+ std::function<QString(const QString&, const QString&, bool)> colorize);
+
+ // accessors
+ void setComment(const QString& comment);
+ QString getComment() const;
+ void setHelpPath(const QString& path);
+ static QHash<QString, QString> getVariableHash();
+ static void setVariableHash(const QHash<QString, QString>& variableHash);
+ void setStartNodes(std::vector<ExecutionNode*> nodes);
+
+ // Aliases
+ QString convertAlias(QString str);
+ void insertAlias(DiceAlias* dice, int i);
+ const QList<DiceAlias*>& getAliases() const;
+ QList<DiceAlias*>* aliases();
+ void setAliases(const QList<DiceAlias*> list);
+ void cleanUpAliases();
+
+ static bool readStringResultParameter(QString& str);
+ static QString replacePlaceHolderFromJson(const QString& source, const QJsonObject& obj);
+
+private:
+ QMap<QString, Dice::CompareOperator> m_logicOp;
+ QMap<QString, Dice::LogicOperation> m_logicOperation;
+ QMap<QString, Dice::ConditionOperator> m_conditionOperation;
+ std::vector<std::pair<QString, Dice::ArithmeticOperator>> m_arithmeticOperation;
+ QMap<QString, DiceOperator> m_mapDiceOp;
+ QMap<QString, OptionOperator> m_OptionOp;
+ QMap<QString, NodeAction> m_nodeActionMap;
+ std::map<QString, Function> m_functionMap;
+ QStringList m_commandList;
+
+ QMap<Dice::ERROR_CODE, QString> m_errorMap;
+ QMap<Dice::ERROR_CODE, QString> m_warningMap;
+ std::vector<ExecutionNode*> m_startNodes;
+
+ QString m_comment;
+
+ static QHash<QString, QString> m_variableHash;
+ QString m_helpPath;
+ QList<DiceAlias*> m_aliasList;
+};
+
+#endif // PARSINGTOOLBOX_H
diff --git a/src/libparser/include/diceparser_qobject/diceparser_qobject_global.h b/src/libparser/include/diceparser_qobject/diceparser_qobject_global.h
new file mode 100644
index 0000000..ea49727
--- /dev/null
+++ b/src/libparser/include/diceparser_qobject/diceparser_qobject_global.h
@@ -0,0 +1,11 @@
+#ifndef DICEPARSER_QOBJECT_GLOBAL_H
+#define DICEPARSER_QOBJECT_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(DICEPARSER_QOBJECT_LIBRARY)
+#define DICEPARSER_QOBJECT_EXPORT Q_DECL_EXPORT
+#else
+#define DICEPARSER_QOBJECT_EXPORT Q_DECL_IMPORT
+#endif
+#endif // DICEPARSER_QOBJECT_GLOBAL_H
diff --git a/src/libparser/include/diceparser_qobject/diceroller.h b/src/libparser/include/diceparser_qobject/diceroller.h
new file mode 100644
index 0000000..72c4e10
--- /dev/null
+++ b/src/libparser/include/diceparser_qobject/diceroller.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * Rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef DICEROLLER_H
+#define DICEROLLER_H
+
+#include <QObject>
+#include <diceparser/diceparser.h>
+
+#include <diceparser_qobject/diceparser_qobject_global.h>
+
+class DICEPARSER_QOBJECT_EXPORT DiceRoller : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal result READ result NOTIFY resultChanged)
+ Q_PROPERTY(QString dicelist READ diceList NOTIFY diceListChanged)
+ Q_PROPERTY(QString resultStr READ resultStr NOTIFY resultStrChanged)
+ Q_PROPERTY(QString command READ command WRITE setCommand NOTIFY commandChanged)
+ Q_PROPERTY(QString error READ error WRITE setError NOTIFY errorOccurs)
+
+public:
+ DiceRoller(QObject* parent= nullptr);
+
+ QString diceList() const;
+ QString resultStr() const;
+ QString command() const;
+ qreal result() const;
+ QString error() const;
+ QList<DiceAlias*>* aliases() const;
+
+ DiceParser* parser();
+
+signals:
+ void resultChanged();
+ void diceListChanged();
+ void resultStrChanged();
+ void commandChanged();
+ void errorOccurs();
+
+public slots:
+ void start();
+ void readErrorAndWarning();
+ void setCommand(const QString& cmd);
+ void setError(const QString& error);
+
+ /*protected:
+ QString diceToText(QList<ExportedDiceResult>& diceList);*/
+
+private:
+ DiceParser m_diceparser;
+ qreal m_result;
+ QString m_diceList;
+ QString m_resultStr;
+ QString m_command;
+ QString m_error;
+};
+
+#endif // DICEROLLER_H
diff --git a/src/libparser/include/diceparser_qobject/qmltypesregister.h b/src/libparser/include/diceparser_qobject/qmltypesregister.h
new file mode 100644
index 0000000..e0b1a09
--- /dev/null
+++ b/src/libparser/include/diceparser_qobject/qmltypesregister.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REGISTER_QML_TYPE_H
+#define REGISTER_QML_TYPE_H
+
+#include <diceparser_qobject/diceparser_qobject_global.h>
+
+DICEPARSER_QOBJECT_EXPORT void registerQmlTypes();
+
+#endif // REGISTER_QML_TYPE_H
diff --git a/src/libparser/node/allsamenode.cpp b/src/libparser/node/allsamenode.cpp
new file mode 100644
index 0000000..3b2f10f
--- /dev/null
+++ b/src/libparser/node/allsamenode.cpp
@@ -0,0 +1,86 @@
+#include "allsamenode.h"
+
+AllSameNode::AllSameNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+
+void AllSameNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != previous_result)
+ {
+ m_result->setPrevious(previous_result);
+ bool allSame= true;
+ int i= 0;
+ qint64 previousValue= 0;
+ if(previous_result->getResultList().size() < 2)
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QStringLiteral("T operator must operate on more than 1 die"));
+ return;
+ }
+ for(auto& die : previous_result->getResultList())
+ {
+ if(i == 0)
+ previousValue= die->getValue();
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ if(previousValue != die->getValue())
+ allSame= false;
+ ++i;
+ }
+
+ while(allSame)
+ {
+ QList<Die*> list= m_diceResult->getResultList();
+ qint64 pValue= 0;
+ int i= 0;
+ for(auto& die : list)
+ {
+ die->roll(true);
+ if(i == 0)
+ pValue= die->getValue();
+ if(pValue != die->getValue())
+ allSame= false;
+ ++i;
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString AllSameNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"AllSameNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 AllSameNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* AllSameNode::getCopy() const
+{
+ return new AllSameNode();
+}
diff --git a/src/libparser/node/allsamenode.h b/src/libparser/node/allsamenode.h
new file mode 100644
index 0000000..e5c1dc2
--- /dev/null
+++ b/src/libparser/node/allsamenode.h
@@ -0,0 +1,33 @@
+#ifndef ALLSAMENODE_H
+#define ALLSAMENODE_H
+
+#include "executionnode.h"
+
+#include "result/diceresult.h"
+#include "validator.h"
+
+class AllSameNode : public ExecutionNode
+{
+public:
+ AllSameNode();
+// virtual ~AllSameNode();
+
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // FILTERNODE_H
diff --git a/src/libparser/node/bind.cpp b/src/libparser/node/bind.cpp
new file mode 100644
index 0000000..490071f
--- /dev/null
+++ b/src/libparser/node/bind.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "bind.h"
+
+BindNode::BindNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void BindNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == m_previousNode)
+ return;
+
+ m_result->setPrevious(previous->getResult());
+ for(auto start : *m_startList)
+ {
+ ExecutionNode* last= getLatestNode(start);
+ if(nullptr != last)
+ {
+ auto tmpResult= last->getResult();
+ while(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ m_diceResult->setHomogeneous(false);
+ for(auto& die : dice->getResultList())
+ {
+ if(!die->hasBeenDisplayed())
+ {
+ Die* tmpdie= new Die(*die);
+ die->displayed();
+ m_diceResult->getResultList().append(tmpdie);
+ }
+ }
+ }
+ tmpResult= tmpResult->getPrevious();
+ }
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+ExecutionNode* BindNode::getLatestNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode() && (next->getNextNode() != this))
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+QString BindNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"Bind Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 BindNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* BindNode::getCopy() const
+{
+ BindNode* node= new BindNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+std::vector<ExecutionNode*>* BindNode::getStartList() const
+{
+ return m_startList;
+}
+
+void BindNode::setStartList(std::vector<ExecutionNode*>* startList)
+{
+ m_startList= startList;
+}
diff --git a/src/libparser/node/bind.h b/src/libparser/node/bind.h
new file mode 100644
index 0000000..71bbfb0
--- /dev/null
+++ b/src/libparser/node/bind.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef BINDNODE_H
+#define BINDNODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The MergeNode class is an ExecutionNode. It is dedicated to merge result of several commands.
+ */
+class BindNode : public ExecutionNode
+{
+public:
+ BindNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ std::vector<ExecutionNode*>* getStartList() const;
+ void setStartList(std::vector<ExecutionNode*>* startList);
+
+private:
+ ExecutionNode* getLatestNode(ExecutionNode* node);
+
+private:
+ DiceResult* m_diceResult;
+ std::vector<ExecutionNode*>* m_startList;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/countexecutenode.cpp b/src/libparser/node/countexecutenode.cpp
new file mode 100644
index 0000000..b45fe37
--- /dev/null
+++ b/src/libparser/node/countexecutenode.cpp
@@ -0,0 +1,76 @@
+#include "countexecutenode.h"
+#include "result/diceresult.h"
+#include "validatorlist.h"
+
+CountExecuteNode::CountExecuteNode() : m_scalarResult(new ScalarResult()), m_validatorList(nullptr)
+{
+ m_result= m_scalarResult;
+}
+void CountExecuteNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+CountExecuteNode::~CountExecuteNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+
+void CountExecuteNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QStringLiteral("No scalar result before Swith/Case operator"));
+ return;
+ }
+ DiceResult* previousResult= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != previousResult)
+ {
+ m_result->setPrevious(previousResult);
+ qint64 sum= 0;
+ std::function<void(Die*, qint64)> f= [&sum](const Die*, qint64 score) { sum+= score; };
+ m_validatorList->validResult(previousResult, true, true, f);
+ m_scalarResult->setValue(sum);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+QString CountExecuteNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"CountExecuteNode %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 CountExecuteNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* CountExecuteNode::getCopy() const
+{
+ CountExecuteNode* node= new CountExecuteNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/countexecutenode.h b/src/libparser/node/countexecutenode.h
new file mode 100644
index 0000000..37b7a4f
--- /dev/null
+++ b/src/libparser/node/countexecutenode.h
@@ -0,0 +1,50 @@
+#ifndef COUNTEXECUTENODE_H
+#define COUNTEXECUTENODE_H
+
+#include "executionnode.h"
+
+#include "result/scalarresult.h"
+
+class ValidatorList;
+/**
+ * @brief The CountExecuteNode class
+ */
+class CountExecuteNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief CountExecuteNode
+ */
+ CountExecuteNode();
+ virtual ~CountExecuteNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ ScalarResult* m_scalarResult;
+ ValidatorList* m_validatorList;
+};
+
+#endif // COUNTEXECUTENODE_H
diff --git a/src/libparser/node/dicerollernode.cpp b/src/libparser/node/dicerollernode.cpp
new file mode 100644
index 0000000..2b00c0a
--- /dev/null
+++ b/src/libparser/node/dicerollernode.cpp
@@ -0,0 +1,121 @@
+#include "dicerollernode.h"
+#include "die.h"
+
+#include <QDebug>
+#include <QThread>
+#include <QThreadPool>
+#include <QTime>
+
+DiceRollerNode::DiceRollerNode(qint64 max, qint64 min)
+ : m_max(max), m_diceResult(new DiceResult()), m_min(min), m_operator(Dice::ArithmeticOperator::PLUS)
+{
+ m_result= m_diceResult;
+}
+void DiceRollerNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ Result* result= previous->getResult();
+ if(nullptr != result)
+ {
+ auto num= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ if(num <= 0)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_DICE_TO_ROLL, QObject::tr("No dice to roll"));
+ }
+ m_diceCount= num > 0 ? static_cast<quint64>(num) : 0;
+ m_result->setPrevious(result);
+
+ auto possibleValue= static_cast<quint64>(std::abs((m_max - m_min) + 1));
+ if(possibleValue < m_diceCount && m_unique)
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr("More unique values asked than possible values (D operator)"));
+ return;
+ }
+
+ for(quint64 i= 0; i < m_diceCount; ++i)
+ {
+ Die* die= new Die();
+ die->setOp(m_operator);
+ die->setBase(m_min);
+ die->setMaxValue(m_max);
+ die->roll();
+ if(m_unique)
+ {
+ const auto& equal= [](const Die* a, const Die* b) { return a->getValue() == b->getValue(); };
+ while(m_diceResult->contains(die, equal))
+ {
+ die->roll(false);
+ }
+ }
+ m_diceResult->insertResult(die);
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+
+quint64 DiceRollerNode::getFaces() const
+{
+ return static_cast<quint64>(std::abs(m_max - m_min) + 1);
+}
+
+std::pair<qint64, qint64> DiceRollerNode::getRange() const
+{
+ return std::make_pair(m_min, m_max);
+}
+QString DiceRollerNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"DiceRollerNode faces: %2\"]").arg(m_id).arg(getFaces());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 DiceRollerNode::getPriority() const
+{
+ qint64 priority= 4;
+ // if(nullptr!=m_nextNode)
+ // {
+ // priority = m_nextNode->getPriority();
+ // }
+ return priority;
+}
+ExecutionNode* DiceRollerNode::getCopy() const
+{
+ DiceRollerNode* node= new DiceRollerNode(m_max, m_min);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+Dice::ArithmeticOperator DiceRollerNode::getOperator() const
+{
+ return m_operator;
+}
+
+void DiceRollerNode::setOperator(const Dice::ArithmeticOperator& dieOperator)
+{
+ m_operator= dieOperator;
+ m_diceResult->setOperator(dieOperator);
+}
+
+bool DiceRollerNode::getUnique() const
+{
+ return m_unique;
+}
+
+void DiceRollerNode::setUnique(bool unique)
+{
+ m_unique= unique;
+}
diff --git a/src/libparser/node/dicerollernode.h b/src/libparser/node/dicerollernode.h
new file mode 100644
index 0000000..52178cb
--- /dev/null
+++ b/src/libparser/node/dicerollernode.h
@@ -0,0 +1,63 @@
+#ifndef DICEROLLERNODE_H
+#define DICEROLLERNODE_H
+
+#include <Qt>
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <utility>
+/**
+ * @brief The DiceRollerNode class rolls dice of one kind.
+ */
+class DiceRollerNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief DiceRollerNode builds an instance
+ * @param faces, number of faces of dices
+ * @param offset, first value of dice.
+ */
+ DiceRollerNode(qint64 max, qint64 min= 1);
+
+ /**
+ * @brief run - starts to roll dice.
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief getFaces accessor
+ * @return the face count
+ */
+ quint64 getFaces() const;
+ std::pair<qint64, qint64> getRange() const;
+
+ /**
+ * @brief toString
+ * @param wl
+ * @return use to generate dot tree;
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return priority for dice roll: 4 (higher)
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+ // private members
+ Dice::ArithmeticOperator getOperator() const;
+ void setOperator(const Dice::ArithmeticOperator& dieOperator);
+
+ bool getUnique() const;
+ void setUnique(bool unique);
+
+private:
+ quint64 m_diceCount;
+ qint64 m_max; /// faces
+ DiceResult* m_diceResult{nullptr};
+ qint64 m_min;
+ Dice::ArithmeticOperator m_operator;
+ bool m_unique{false};
+};
+
+#endif // DICEROLLERNODE_H
diff --git a/src/libparser/node/executionnode.cpp b/src/libparser/node/executionnode.cpp
new file mode 100644
index 0000000..4545934
--- /dev/null
+++ b/src/libparser/node/executionnode.cpp
@@ -0,0 +1,101 @@
+#include "executionnode.h"
+
+#include <QUuid>
+
+ExecutionNode::ExecutionNode()
+ : m_previousNode(nullptr)
+ , m_result(nullptr)
+ , m_nextNode(nullptr)
+ , m_errors(QMap<Dice::ERROR_CODE, QString>())
+ , m_id(QString("\"%1\"").arg(QUuid::createUuid().toString()))
+{
+}
+ExecutionNode::~ExecutionNode()
+{
+ if(nullptr != m_result)
+ {
+ delete m_result;
+ m_result= nullptr;
+ }
+ if(nullptr != m_nextNode)
+ {
+ delete m_nextNode;
+ m_nextNode= nullptr;
+ }
+}
+
+Result* ExecutionNode::getResult()
+{
+ return m_result;
+}
+void ExecutionNode::setNextNode(ExecutionNode* node)
+{
+ m_nextNode= node;
+}
+void ExecutionNode::setPreviousNode(ExecutionNode* node)
+{
+ m_previousNode= node;
+}
+ExecutionNode* ExecutionNode::getNextNode()
+{
+ return m_nextNode;
+}
+QMap<Dice::ERROR_CODE, QString> ExecutionNode::getExecutionErrorMap()
+{
+ if(nullptr != m_nextNode)
+ {
+ auto const& keys= m_nextNode->getExecutionErrorMap().keys();
+ for(auto& key : keys)
+ {
+ m_errors.insert(key, m_nextNode->getExecutionErrorMap().value(key));
+ }
+ }
+ return m_errors;
+}
+QString ExecutionNode::getHelp()
+{
+ return QString();
+}
+ExecutionNode* ExecutionNode::getPreviousNode() const
+{
+ return m_previousNode;
+}
+void ExecutionNode::generateDotTree(QString& s)
+{
+ auto str= toString(true);
+ if(s.contains(str))
+ return;
+ s.append(toString(true));
+ s.append(";\n");
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ // s.append(" [label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+ }
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+}
+qint64 ExecutionNode::getScalarResult()
+{
+ if(m_result == nullptr)
+ return 0;
+ return m_result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+}
diff --git a/src/libparser/node/executionnode.h b/src/libparser/node/executionnode.h
new file mode 100644
index 0000000..d1bdf66
--- /dev/null
+++ b/src/libparser/node/executionnode.h
@@ -0,0 +1,102 @@
+#ifndef EXECUTIONNODE_H
+#define EXECUTIONNODE_H
+
+#include "result/result.h"
+#include <diceparser/diceparserhelper.h>
+
+/**
+ * @brief The ExecutionNode class
+ */
+class ExecutionNode
+{
+public:
+ /**
+ * @brief ExecutionNode
+ */
+ ExecutionNode();
+ /**
+ * @brief ~ExecutionNode
+ */
+ virtual ~ExecutionNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr)= 0;
+ /**
+ * @brief getResult
+ * @return
+ */
+ virtual Result* getResult();
+ /**
+ * @brief setNextNode
+ */
+ void setNextNode(ExecutionNode*);
+ /**
+ * @brief getNextNode
+ * @return
+ */
+ ExecutionNode* getNextNode();
+ /**
+ * @brief getPreviousNode
+ * @return
+ */
+ virtual ExecutionNode* getPreviousNode() const;
+ void setPreviousNode(ExecutionNode* node);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const= 0;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const= 0;
+ /**
+ * @brief getErrorList
+ * @return
+ */
+ virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap();
+
+ /**
+ * @brief generateDotTree
+ */
+ virtual void generateDotTree(QString&);
+
+ /**
+ * @brief getHelp
+ * @return
+ */
+ virtual QString getHelp();
+
+ /**
+ * @brief getCopy
+ * @return should return a copy of that node.
+ */
+ virtual ExecutionNode* getCopy() const= 0;
+
+ virtual qint64 getScalarResult();
+
+protected:
+ /**
+ * @brief m_nextNode
+ */
+ ExecutionNode* m_previousNode= nullptr;
+ /**
+ * @brief m_result
+ */
+ Result* m_result= nullptr;
+ /**
+ * @brief m_nextNode
+ */
+ ExecutionNode* m_nextNode= nullptr;
+ /**
+ * @brief m_errors
+ */
+ QMap<Dice::ERROR_CODE, QString> m_errors;
+
+ QString m_id;
+};
+
+#endif // EXECUTIONNODE_H
diff --git a/src/libparser/node/explodedicenode.cpp b/src/libparser/node/explodedicenode.cpp
new file mode 100644
index 0000000..1546883
--- /dev/null
+++ b/src/libparser/node/explodedicenode.cpp
@@ -0,0 +1,117 @@
+#include "explodedicenode.h"
+#include "validatorlist.h"
+
+ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void ExplodeDiceNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != previous) && (nullptr != previous->getResult()))
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previous_result);
+ if(nullptr != previous_result)
+ {
+ Die* exampleDie;
+ for(auto& die : previous_result->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ exampleDie= tmpdie;
+ }
+
+ // QList<Die*> list= m_diceResult->getResultList();
+
+ bool hasExploded= false;
+ std::function<void(Die*, qint64)> f= [&hasExploded, this](Die* die, qint64) {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE
+ == m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())))
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition (%1) cause an endless loop with this dice: %2")
+ .arg(toString(true))
+ .arg(QStringLiteral("d[%1,%2]")
+ .arg(static_cast<int>(die->getBase()))
+ .arg(static_cast<int>(die->getMaxValue()))));
+ }
+ hasExploded= true;
+ die->roll(true);
+ };
+ do
+ {
+ hasExploded= false;
+ m_validatorList->validResult(m_diceResult, false, false, f);
+ } while(hasExploded);
+
+ /*for(auto& die : list)
+ {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE
+ == m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())))
+ {
+
+ continue;
+ }
+
+ while(m_validatorList->hasValid(die, false))
+ {
+ die->roll(true);
+ }
+ }*/
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+ExplodeDiceNode::~ExplodeDiceNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+void ExplodeDiceNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+QString ExplodeDiceNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"ExplodeDiceNode %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ExplodeDiceNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* ExplodeDiceNode::getCopy() const
+{
+ ExplodeDiceNode* node= new ExplodeDiceNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/explodedicenode.h b/src/libparser/node/explodedicenode.h
new file mode 100644
index 0000000..77b4a44
--- /dev/null
+++ b/src/libparser/node/explodedicenode.h
@@ -0,0 +1,29 @@
+#ifndef EXPLOSEDICENODE_H
+#define EXPLOSEDICENODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValidatorList;
+
+/**
+ * @brief The ExplodeDiceNode class explode dice while is valid by the validator.
+ */
+class ExplodeDiceNode : public ExecutionNode
+{
+public:
+ ExplodeDiceNode();
+ virtual ~ExplodeDiceNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual void setValidatorList(ValidatorList*);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+protected:
+ DiceResult* m_diceResult;
+ ValidatorList* m_validatorList= nullptr;
+};
+
+#endif // EXPLOSEDICENODE_H
diff --git a/src/libparser/node/filternode.cpp b/src/libparser/node/filternode.cpp
new file mode 100644
index 0000000..b72b6e1
--- /dev/null
+++ b/src/libparser/node/filternode.cpp
@@ -0,0 +1,94 @@
+#include "filternode.h"
+#include "validatorlist.h"
+
+FilterNode::FilterNode() : m_diceResult(new DiceResult()), m_eachValue(false)
+{
+ m_result= m_diceResult;
+}
+
+FilterNode::~FilterNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ }
+}
+void FilterNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+void FilterNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previousDiceResult);
+
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList2;
+ std::function<void(Die*, qint64)> f= [&diceList2](Die* die, qint64) {
+ if(die == nullptr)
+ return;
+ Die* tmpdie= new Die(*die);
+ diceList2.append(tmpdie);
+ die->displayed();
+ };
+ m_validatorList->validResult(previousDiceResult, true, true, f);
+
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ diceList.erase(std::remove_if(diceList.begin(), diceList.end(),
+ [&diceList2](Die* die) { return diceList2.contains(die); }),
+ diceList.end());
+ for(Die* tmp : diceList)
+ {
+ tmp->setHighlighted(false);
+ tmp->setDisplayed(true);
+ }
+
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+
+QString FilterNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"FilterNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 FilterNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+
+ return priority;
+}
+ExecutionNode* FilterNode::getCopy() const
+{
+ FilterNode* node= new FilterNode();
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/filternode.h b/src/libparser/node/filternode.h
new file mode 100644
index 0000000..7af6fe2
--- /dev/null
+++ b/src/libparser/node/filternode.h
@@ -0,0 +1,40 @@
+#ifndef FILTERNODE_H
+#define FILTERNODE_H
+
+#include "executionnode.h"
+
+#include "result/diceresult.h"
+
+class ValidatorList;
+
+class FilterNode : public ExecutionNode
+{
+public:
+ FilterNode();
+ virtual ~FilterNode();
+
+ virtual void run(ExecutionNode* previous);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withLabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+ ValidatorList* m_validatorList;
+ bool m_eachValue;
+};
+
+#endif // FILTERNODE_H
diff --git a/src/libparser/node/forloopnode.cpp b/src/libparser/node/forloopnode.cpp
new file mode 100644
index 0000000..aba6ff4
--- /dev/null
+++ b/src/libparser/node/forloopnode.cpp
@@ -0,0 +1,103 @@
+#include "forloopnode.h"
+
+#include "die.h"
+
+MockNode::MockNode() {}
+
+void MockNode::run(ExecutionNode* node)
+{
+ return;
+}
+
+void MockNode::setResult(Result* result)
+{
+ m_result= result;
+}
+
+QString MockNode::toString(bool) const
+{
+ return {};
+};
+qint64 MockNode::getPriority() const
+{
+ return 0;
+}
+ExecutionNode* MockNode::getCopy() const
+{
+ return new MockNode();
+}
+// end mocknode
+
+ForLoopNode::ForLoopNode() : m_diceResult(new DiceResult) {}
+
+void ForLoopNode::setInternal(ExecutionNode* node)
+{
+ m_internal.reset(node);
+}
+
+void ForLoopNode::run(ExecutionNode* previous)
+{
+ if(nullptr != previous)
+ {
+ auto prevResult= dynamic_cast<DiceResult*>(previous->getResult());
+ if(nullptr != prevResult)
+ {
+ m_diceResult->setPrevious(prevResult);
+ QList<Die*> diceList= prevResult->getResultList();
+ for(Die* dice : diceList)
+ {
+ MockNode node;
+ DiceResult diceResult;
+ diceResult.insertResult(dice);
+ node.setResult(&diceResult);
+ m_internal->run(&node);
+
+ auto tmp= m_internal.get();
+ while(nullptr != tmp->getNextNode())
+ {
+ tmp= tmp->getNextNode();
+ }
+ Result* internalResult= tmp->getResult();
+ auto value= internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+
+ Die* neodie= new Die();
+ *neodie= *dice;
+ neodie->setValue(value);
+ m_diceResult->insertResult(neodie);
+ node.setResult(nullptr);
+ diceResult.clear();
+ dice->displayed();
+ }
+ }
+ }
+ m_result= m_diceResult;
+ if(m_nextNode != nullptr)
+ m_nextNode->run(this);
+}
+
+qint64 ForLoopNode::getPriority() const
+{
+ return 2;
+}
+
+QString ForLoopNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"ForLoopNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+ExecutionNode* ForLoopNode::getCopy() const
+{
+ auto node= new ForLoopNode();
+ if(m_internal)
+ {
+ node->setInternal(m_internal->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/forloopnode.h b/src/libparser/node/forloopnode.h
new file mode 100644
index 0000000..a9acf20
--- /dev/null
+++ b/src/libparser/node/forloopnode.h
@@ -0,0 +1,36 @@
+#ifndef FORLOOPNODE_H
+#define FORLOOPNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <memory>
+
+class MockNode : public ExecutionNode
+{
+public:
+ MockNode();
+ void run(ExecutionNode* node);
+ void setResult(Result* result);
+ QString toString(bool withLabel) const;
+ qint64 getPriority() const;
+ ExecutionNode* getCopy() const;
+};
+
+class ForLoopNode : public ExecutionNode
+{
+public:
+ ForLoopNode();
+ void run(ExecutionNode* previous);
+
+ void setInternal(ExecutionNode* internal);
+
+ QString toString(bool withLabel) const;
+ qint64 getPriority() const;
+ ExecutionNode* getCopy() const;
+
+private:
+ std::unique_ptr<ExecutionNode> m_internal;
+ DiceResult* m_diceResult;
+};
+
+#endif // FORLOOPNODE_H
diff --git a/src/libparser/node/groupnode.cpp b/src/libparser/node/groupnode.cpp
new file mode 100644
index 0000000..860d758
--- /dev/null
+++ b/src/libparser/node/groupnode.cpp
@@ -0,0 +1,312 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "groupnode.h"
+#include "result/diceresult.h"
+//-------------------------------
+int DieGroup::getSum() const
+{
+ int sum= 0;
+ for(int i : *this)
+ {
+ sum+= i;
+ }
+ return sum;
+}
+
+void DieGroup::removeValue(DieGroup i)
+{
+ for(auto x : i)
+ {
+ removeOne(x);
+ }
+}
+
+int DieGroup::getLost() const
+{
+ return getSum() - m_exceptedValue;
+}
+
+qint64 DieGroup::getExceptedValue() const
+{
+ return m_exceptedValue;
+}
+
+void DieGroup::setExceptedValue(qint64 exceptedValue)
+{
+ m_exceptedValue= exceptedValue;
+}
+
+//---------------------
+GroupNode::GroupNode(bool complexOutput)
+ : m_scalarResult(new ScalarResult), m_stringResult(new StringResult), m_complexOutput(complexOutput)
+{
+}
+
+void GroupNode::run(ExecutionNode* previous)
+{
+ if(m_complexOutput)
+ m_result= m_stringResult;
+ else
+ m_result= m_scalarResult;
+
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ auto list= dice->getResultList();
+ DieGroup allResult;
+ for(auto& die : list)
+ {
+ allResult << die->getListValue();
+ }
+ std::sort(allResult.begin(), allResult.end(), std::greater<qint64>());
+ if(allResult.getSum() > m_groupValue)
+ {
+ auto copy= allResult;
+ auto const die= getGroup(allResult);
+
+ for(auto list : die)
+ {
+ for(auto val : list)
+ {
+ copy.removeOne(val);
+ }
+ }
+ m_scalarResult->setValue(die.size());
+ QStringList list;
+ for(auto group : die)
+ {
+ QStringList values;
+ std::transform(group.begin(), group.end(), std::back_inserter(values),
+ [](qint64 val) { return QString::number(val); });
+ list << QStringLiteral("{%1}").arg(values.join(","));
+ }
+ QStringList unused;
+ std::transform(copy.begin(), copy.end(), std::back_inserter(unused),
+ [](qint64 val) { return QString::number(val); });
+ if(!unused.isEmpty())
+ m_stringResult->addText(
+ QStringLiteral("%1 (%2 - [%3])").arg(die.size()).arg(list.join(",")).arg(unused.join(",")));
+ else
+ m_stringResult->addText(QStringLiteral("%1 (%2)").arg(die.size()).arg(list.join(",")));
+ }
+ else
+ {
+ m_scalarResult->setValue(0);
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString GroupNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SplitNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 GroupNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* GroupNode::getCopy() const
+{
+ GroupNode* node= new GroupNode(m_complexOutput);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+int GroupNode::getGroupValue() const
+{
+ return m_groupValue;
+}
+
+void GroupNode::setGroupValue(qint64 groupValue)
+{
+ m_groupValue= groupValue;
+}
+
+bool GroupNode::composeWithPrevious(DieGroup previous, qint64 first, qint64 current, DieGroup& addValue)
+{
+ if(previous.getSum() + first + current == m_groupValue)
+ {
+ addValue.append(previous);
+ addValue.append(first);
+ addValue.append(current);
+ return true;
+ }
+
+ if(previous.isEmpty())
+ return false;
+
+ int maxComboLength= previous.size();
+ bool hasReachMax= false;
+
+ QList<DieGroup> possibleUnion;
+ for(auto va : previous)
+ {
+ DieGroup dieG;
+ dieG.append(va);
+ possibleUnion.append(dieG);
+ }
+
+ while(!hasReachMax)
+ {
+ auto tmpValues= previous;
+ QList<DieGroup> possibleTmp;
+ for(auto& diaG : possibleUnion)
+ {
+ if(tmpValues.isEmpty())
+ break;
+ tmpValues.removeValue(diaG);
+
+ for(auto& value : tmpValues)
+ {
+ DieGroup dia;
+ dia.append(diaG);
+ dia.append(value);
+ if(dia.size() >= maxComboLength - 1)
+ hasReachMax= true;
+ else
+ possibleTmp.append(dia);
+ }
+ }
+ if(possibleTmp.isEmpty())
+ hasReachMax= true;
+ else
+ {
+ possibleTmp.append(possibleUnion);
+ possibleUnion= possibleTmp;
+ }
+ }
+ std::sort(possibleUnion.begin(), possibleUnion.end(),
+ [=](const DieGroup& a, const DieGroup& b) { return a.getLost() > b.getLost(); });
+ bool found= false;
+ for(int i= 0; (!found && i < possibleUnion.size()); ++i)
+ {
+ auto& value= possibleUnion.at(i);
+ if(value.getSum() + current + first >= m_groupValue)
+ {
+ addValue << value << current << first;
+ found= true;
+ }
+ }
+ return found;
+}
+
+QList<DieGroup> GroupNode::getGroup(DieGroup values)
+{
+ if(values.isEmpty())
+ return {};
+
+ auto first= values.takeFirst();
+
+ QList<DieGroup> result;
+ QMap<qint64, DieGroup> loseMap;
+ if(first >= m_groupValue)
+ {
+ DieGroup group;
+ group << first;
+ loseMap[0]= group;
+ }
+ else
+ {
+ auto it= values.rbegin();
+ bool foundPerfect= false;
+ qint64 cumuledValue= 0;
+ DieGroup previousValue;
+ while((values.rend() != it) && !foundPerfect)
+ {
+ if(first + *it == m_groupValue)
+ {
+ foundPerfect= true;
+ DieGroup group;
+ group << first << *it;
+ loseMap[0]= group;
+ }
+ else if(first + *it > m_groupValue)
+ {
+ DieGroup group;
+ group << first << *it;
+ loseMap[first + *it - m_groupValue]= group;
+ }
+ else if(first + *it + cumuledValue == m_groupValue)
+ {
+ DieGroup group;
+ group << first << *it << previousValue;
+ foundPerfect= true;
+ loseMap[0]= group;
+ }
+ else if(first + *it + cumuledValue > m_groupValue)
+ {
+ DieGroup group;
+ group.setExceptedValue(m_groupValue);
+ auto b= composeWithPrevious(previousValue, first, *it, group);
+ if(b)
+ loseMap[group.getLost()]= group;
+ }
+ previousValue << *it;
+ cumuledValue+= *it;
+ ++it;
+ }
+ }
+ if(!loseMap.isEmpty())
+ {
+ DieGroup die= loseMap.first();
+ result.append(die);
+ DieGroup valueToRemove= die;
+ if(!valueToRemove.isEmpty())
+ {
+ valueToRemove.removeFirst();
+ values.removeValue(valueToRemove);
+
+ if(values.getSum() >= m_groupValue)
+ {
+ result.append(getGroup(values));
+ }
+ }
+ }
+ return result;
+}
diff --git a/src/libparser/node/groupnode.h b/src/libparser/node/groupnode.h
new file mode 100644
index 0000000..d037080
--- /dev/null
+++ b/src/libparser/node/groupnode.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef GROUPNODE_H
+#define GROUPNODE_H
+
+#include "node/executionnode.h"
+#include "result/scalarresult.h"
+#include "result/stringresult.h"
+#include <QList>
+
+class DieGroup : public QList<qint64>
+{
+public:
+ int getSum() const;
+ void removeValue(DieGroup);
+
+ int getLost() const;
+
+ qint64 getExceptedValue() const;
+ void setExceptedValue(qint64 exceptedValue);
+
+private:
+ qint64 m_exceptedValue= 0;
+};
+/**
+ * @brief The GroupNode class is an ExecutionNode.
+ */
+class GroupNode : public ExecutionNode
+{
+public:
+ GroupNode(bool complexOutput= false);
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+
+ int getGroupValue() const;
+ void setGroupValue(qint64 groupValue);
+
+ QList<DieGroup> getGroup(DieGroup);
+
+protected:
+ bool composeWithPrevious(DieGroup previous, qint64 first, qint64 current, DieGroup& addValue);
+
+private:
+ ScalarResult* m_scalarResult;
+ StringResult* m_stringResult;
+ qint64 m_groupValue;
+ QList<DieGroup> m_groupsList;
+ bool m_complexOutput= false;
+};
+
+#endif // GROUPNODE_H
diff --git a/src/libparser/node/helpnode.cpp b/src/libparser/node/helpnode.cpp
new file mode 100644
index 0000000..8ab48a9
--- /dev/null
+++ b/src/libparser/node/helpnode.cpp
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "helpnode.h"
+
+HelpNode::HelpNode() : m_path("https://github.com/Rolisteam/DiceParser/blob/master/HelpMe.md")
+{
+ m_result= new StringResult();
+}
+void HelpNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ StringResult* txtResult= dynamic_cast<StringResult*>(m_result);
+ txtResult->setHighLight(false);
+
+ if((nullptr == previous) && (txtResult != nullptr))
+ {
+ txtResult->addText(QObject::tr("Rolisteam Dice Parser:\n"
+ "\n"
+ "Example (with ! as prefix):\n"
+ "!2d6\n"
+ "!1d20\n"
+ "!6d10e10k3 (L5R)\n"
+ "\n"
+ "Full documentation at: %1")
+ .arg(m_path));
+ /*txtResult->setText(QObject::tr("Rolisteam Dice Parser:\n"
+ "\n"
+ "Example (with ! as prefix):\n"
+ "!2d6\n"
+ "!1d20\n"
+ "\n"
+ "Operator list:\n"
+ "\n"
+ "k : Keep : 2d10k1 => roll two 10-sided dice and keep the
+ higher one (kl1 for smaller one)\n" "K : Keep And Explode : 2d10K1 => Equivalent of 2d10e10k1\n" "s :
+ Sort : 8d10 => roll eight 10-sided dice and sort the result list\n" "c : Count :
+ 8d10c[>7] => roll eight 10-sided dice and count how many dice are higher than 7\n" "r : Reroll :
+ 8d6r1 => roll eight 6-sided dice and reroll dice once if its result is 1. (result of the reroll can be
+ 1)\n" "e : Explode : 8d10e10 => roll eight 10-sided dice and while dice makes a 10 it is
+ reroll. The result is added to those dice.\n" "a : Reroll and add : 8d6a1 => roll eight 6-sided dice
+ and reroll dice once and the result is added at 1\n" "m : Merge : 1d20;1d10mk1 => roll one 20-side
+ die and one 10-sided die and keep the higher die\n" "i : if : 1d100i[=100]{\"jackpot\"} => Roll
+ one 100-side die and display \"jackpot\" if the die result is 100.\n" "f : filter : 4d10f[!=4] =>
+ roll four 10-sided dice and ignore all dice with 4 as result"
+ "; : Next instruction : 1d20;2d10;3d8 => roll one 20-sided die, two 10-sided
+ dice and three 8-sided dice \n" "g : Group : 8d10g10 => count how many group of 10 it is
+ possible to do (according to rule of 7th sea).\n"
+ "# : Comment : 1d2 #flip coin=> display flip coin as comment of 1 or 2
+ result.\n"
+ "\n"
+ "Validator:\n"
+ "\n"
+ "Supported conditions: >,<,=,>=,<=,!=\n"
+ "Supported operators: % (modulo), &,^,| \n"
+ "\n"
+ " Examples:\n"
+ "\n"
+ "c[>7 & %2=0] : count how many dice are higher than 7 and even\n"
+ "c[>7 | %2=0] : count how many dice are higher than 7 or even\n"
+ "c[>7 ^ %2=0] : count how many dice are higher than 7 or even but not higher
+ than 7 and even\n"
+ "\n"
+ "List:\n"
+ "\n"
+ "1L[green,blue] => pick value from the list (green or blue)\n"
+ "2L[green,blue] => pick two values from the list (green,green | green,blue |
+ blue,green | blue,blue)\n" "2Lu[green,blue] => pick two unique values from the list (green,blue |
+ blue,green)\n"
+ "\n"
+ "Arithmetic\n"
+ "\n"
+ "8+8+8 => 24\n"
+ "24-4 => 20\n"
+ "(3+4)*2 => 14\n"
+ "7/2 => 3.5\n"
+ "2^4 => 16\n"
+ "1d6+6 => roll one 6-sided die and add 6 to its result\n"
+ "(2d4+2)d10 => roll two 4-sided dice, add 2 to the result[2;8] then roll from
+ four to ten 10-sided dice\n"
+ "\n"
+ "Full documentation at: %1").arg(m_path));*/
+ m_result->setPrevious(nullptr);
+ }
+ else if(nullptr != previous)
+ {
+ txtResult->addText(previous->getHelp());
+ m_result->setPrevious(previous->getResult());
+ }
+ txtResult->finished();
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString HelpNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"Rolisteam Dice Parser:\nFull documentation at: %2\"]").arg(m_id, m_path);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 HelpNode::getPriority() const
+{
+ return 0;
+}
+void HelpNode::setHelpPath(QString path)
+{
+ m_path= path;
+}
+
+ExecutionNode* HelpNode::getCopy() const
+{
+ HelpNode* node= new HelpNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/helpnode.h b/src/libparser/node/helpnode.h
new file mode 100644
index 0000000..a333c6d
--- /dev/null
+++ b/src/libparser/node/helpnode.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef HELPNODE_H
+#define HELPNODE_H
+#include "executionnode.h"
+
+#include <QObject>
+#include <QString>
+
+#include "result/stringresult.h"
+
+/**
+ * @brief The HelpNode class
+ */
+class HelpNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief HelpNode
+ */
+ HelpNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ void run(ExecutionNode* previous);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief setHelpPath
+ * @param path
+ */
+ void setHelpPath(QString path);
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ QString m_path;
+};
+
+#endif // HELPNODE_H
diff --git a/src/libparser/node/ifnode.cpp b/src/libparser/node/ifnode.cpp
new file mode 100644
index 0000000..8de3cd5
--- /dev/null
+++ b/src/libparser/node/ifnode.cpp
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "ifnode.h"
+#include "result/diceresult.h"
+#include "validatorlist.h"
+
+PartialDiceRollNode::PartialDiceRollNode() : m_diceResult(new DiceResult)
+{
+ m_result= m_diceResult;
+}
+
+void PartialDiceRollNode::insertDie(Die* die)
+{
+ m_diceResult->insertResult(die);
+}
+
+void PartialDiceRollNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ Result* presult= previous->getResult();
+ if(nullptr != presult)
+ {
+ m_result->setPrevious(presult);
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+ExecutionNode* PartialDiceRollNode::getCopy() const
+{
+ return new PartialDiceRollNode();
+}
+qint64 PartialDiceRollNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
+
+QString PartialDiceRollNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"PartialDiceRollNode \"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+DiceResult* getFirstDiceResult(Result* result)
+{
+ DiceResult* found= nullptr;
+
+ if(nullptr == result)
+ return found;
+ do
+ {
+ found= dynamic_cast<DiceResult*>(result);
+ result= result->getPrevious();
+ } while((nullptr == found) && (result != nullptr));
+
+ return found;
+}
+
+IfNode::IfNode() : m_conditionType(Dice::AllOfThem), m_true(nullptr), m_false(nullptr)
+{
+ // m_result = new DiceResult();
+}
+
+IfNode::~IfNode()
+{
+ m_result= nullptr;
+}
+
+void IfNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ ExecutionNode* previousLoop= previous;
+ ExecutionNode* nextNode= nullptr;
+ bool runNext= (nullptr == m_nextNode) ? false : true;
+ Result* previousResult= previous->getResult();
+ m_result= previousResult->getCopy();
+
+ if(nullptr != m_result)
+ {
+ qreal value= previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+
+ if(nullptr != m_validatorList)
+ {
+ DiceResult* previousDiceResult= getFirstDiceResult(previousResult);
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ if(m_conditionType == Dice::OnEach)
+ {
+ for(Die* dice : diceList)
+ {
+ auto diceNode= new PartialDiceRollNode();
+ diceNode->insertDie(new Die(*dice));
+ if(m_validatorList->hasValid(dice, true, true))
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+
+ if(nullptr != nextNode)
+ {
+ if(nullptr == previousLoop->getNextNode())
+ {
+ previousLoop->setNextNode(nextNode);
+ }
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ diceNode->setNextNode(nextNode);
+ diceNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+ else if((m_conditionType == Dice::OneOfThem) || (m_conditionType == Dice::AllOfThem))
+ {
+ bool trueForAll= true;
+ bool falseForAll= true;
+
+ bool oneIsTrue= false;
+ bool oneIsFalse= false;
+
+ for(Die* dice : diceList)
+ {
+ bool result= m_validatorList->hasValid(dice, true, true);
+ trueForAll= trueForAll ? result : false;
+ falseForAll= falseForAll ? result : false;
+
+ oneIsTrue|= result;
+ oneIsFalse= !result ? true : oneIsFalse;
+ }
+ if(m_conditionType == Dice::OneOfThem)
+ {
+ if(oneIsTrue)
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else // if(oneIsFalse)
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+ }
+ else if(m_conditionType == Dice::AllOfThem)
+ {
+ if(trueForAll)
+ {
+ nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy();
+ }
+ else // if(falseForAll)
+ {
+ nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy();
+ }
+ }
+
+ if(nullptr != nextNode)
+ {
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ nextNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+
+ if(m_conditionType == Dice::OnScalar)
+ {
+ Die dice;
+ auto val= static_cast<qint64>(value);
+ dice.setValue(val);
+ dice.insertRollValue(val);
+ dice.setMaxValue(val);
+ if(m_validatorList->hasValid(&dice, true, true))
+ {
+ nextNode= m_true;
+ }
+ else
+ {
+ nextNode= m_false;
+ }
+ if(nullptr != nextNode)
+ {
+ if(nullptr == m_nextNode)
+ {
+ m_nextNode= nextNode;
+ }
+ nextNode->run(previousLoop);
+ previousLoop= getLeafNode(nextNode);
+ }
+ }
+ }
+ }
+
+ if((nullptr != m_nextNode) && (runNext))
+ {
+ m_nextNode->run(previousLoop);
+ }
+}
+
+void IfNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+void IfNode::setInstructionTrue(ExecutionNode* node)
+{
+ m_true= node;
+}
+
+void IfNode::setInstructionFalse(ExecutionNode* node)
+{
+ m_false= node;
+}
+void IfNode::generateDotTree(QString& s)
+{
+ s.append(toString(true));
+ s.append(";\n");
+
+ if((nullptr != m_true) && (m_true != m_nextNode))
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_true->toString(false));
+ s.append("[label=\"true" + m_validatorList->toString() + "\"];\n");
+
+ m_true->generateDotTree(s);
+ }
+ if((nullptr != m_false) && (m_false != m_nextNode))
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_false->toString(false));
+ s.append("[label=\"false\"];\n");
+ m_false->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\"];\n");
+ m_result->generateDotTree(s);
+ }
+ }
+}
+
+QString IfNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"IfNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 IfNode::getPriority() const
+{
+ return 0;
+}
+
+ExecutionNode* IfNode::getLeafNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode())
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+
+Dice::ConditionType IfNode::getConditionType() const
+{
+ return m_conditionType;
+}
+
+void IfNode::setConditionType(const Dice::ConditionType& conditionType)
+{
+ m_conditionType= conditionType;
+}
+ExecutionNode* IfNode::getCopy() const
+{
+ IfNode* node= new IfNode();
+
+ node->setConditionType(m_conditionType);
+ if(nullptr != m_validatorList)
+ {
+ node->setValidatorList(m_validatorList->getCopy());
+ }
+ if(nullptr != m_false)
+ {
+ node->setInstructionFalse(m_false->getCopy());
+ }
+ if(nullptr != m_true)
+ {
+ node->setInstructionTrue(m_true->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/ifnode.h b/src/libparser/node/ifnode.h
new file mode 100644
index 0000000..912d65c
--- /dev/null
+++ b/src/libparser/node/ifnode.h
@@ -0,0 +1,117 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef IFNODE_H
+#define IFNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <diceparser/diceparserhelper.h>
+
+class ValidatorList;
+class PartialDiceRollNode : public ExecutionNode
+{
+public:
+ PartialDiceRollNode();
+
+ void insertDie(Die* die);
+ virtual void run(ExecutionNode* previous= nullptr) override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+ virtual QString toString(bool withLabel) const override;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+/**
+ * @brief The ifNode class explode dice while is valid by the validator.
+ */
+class IfNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief IfNode
+ */
+ IfNode();
+ /**
+ * @brief ~IfNode
+ */
+ virtual ~IfNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief setInstructionTrue
+ */
+ virtual void setInstructionTrue(ExecutionNode*);
+ /**
+ * @brief setInstructionFalse
+ */
+ virtual void setInstructionFalse(ExecutionNode*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ /**
+ * @brief generateDotTree
+ */
+ virtual void generateDotTree(QString&);
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+ /**
+ * @brief getConditionType
+ * @return
+ */
+ Dice::ConditionType getConditionType() const;
+
+ /**
+ * @brief setConditionType
+ * @param conditionType
+ */
+ void setConditionType(const Dice::ConditionType& conditionType);
+
+protected:
+ ExecutionNode* getLeafNode(ExecutionNode* node);
+
+protected:
+ ValidatorList* m_validatorList= nullptr;
+ Dice::ConditionType m_conditionType;
+
+ ExecutionNode* m_true;
+ ExecutionNode* m_false;
+};
+#endif
diff --git a/src/libparser/node/jumpbackwardnode.cpp b/src/libparser/node/jumpbackwardnode.cpp
new file mode 100644
index 0000000..9fa0f45
--- /dev/null
+++ b/src/libparser/node/jumpbackwardnode.cpp
@@ -0,0 +1,168 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "jumpbackwardnode.h"
+#include <QDebug>
+
+JumpBackwardNode::JumpBackwardNode()
+{
+ m_previousNode= nullptr;
+ m_backwardNode= nullptr;
+ m_diceResult= new DiceResult();
+ m_result= m_diceResult;
+}
+
+qint64 JumpBackwardNode::getPriority() const
+{
+ return 4;
+}
+QString JumpBackwardNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"JumpBackwardNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+void JumpBackwardNode::generateDotTree(QString& s)
+{
+ s.append(toString(true));
+ s.append(";\n");
+
+ if(nullptr != m_backwardNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_backwardNode->toString(false));
+ s.append("[label=\"backward\"];\n");
+ // m_backwardNode->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"next\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\"];\n");
+ m_result->generateDotTree(s);
+ }
+ }
+}
+
+void JumpBackwardNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ ExecutionNode* parent= previous;
+ bool found= false;
+ // int i = 3;
+ Result* result= nullptr;
+ while((nullptr != parent) && (!found))
+ {
+ result= parent->getResult();
+ if(nullptr != result)
+ {
+ //--i;
+ if(/*(i==0)&&*/ (result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ found= true;
+ m_backwardNode= parent;
+ }
+ else
+ {
+ JumpBackwardNode* jpNode= dynamic_cast<JumpBackwardNode*>(parent);
+ if(nullptr != jpNode)
+ {
+ found= true;
+ m_backwardNode= parent;
+ }
+ }
+ }
+ if(!found)
+ {
+ parent= parent->getPreviousNode();
+ }
+ }
+ if(nullptr == result)
+ {
+ m_errors.insert(
+ Dice::ERROR_CODE::DIE_RESULT_EXPECTED,
+ QObject::tr(" The @ operator expects dice result. Please check the documentation to fix your command."));
+ }
+ else
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != diceResult)
+ {
+ for(auto& die : diceResult->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ //*tmpdie= *die;
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ }
+ }
+
+ m_result->setPrevious(previous->getResult());
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ if(nullptr != diceResult)
+ {
+ for(int i= 0; i < diceResult->getResultList().size(); ++i)
+ {
+ Die* tmp= diceResult->getResultList().at(i);
+ Die* tmp2= m_diceResult->getResultList().at(i);
+ if(tmp->isHighlighted())
+ {
+ tmp2->setHighlighted(true);
+ }
+ }
+ }
+ }
+}
+
+ExecutionNode* JumpBackwardNode::getCopy() const
+{
+ JumpBackwardNode* node= new JumpBackwardNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/jumpbackwardnode.h b/src/libparser/node/jumpbackwardnode.h
new file mode 100644
index 0000000..598a540
--- /dev/null
+++ b/src/libparser/node/jumpbackwardnode.h
@@ -0,0 +1,68 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef JUMPBACKWARDNODE_H
+#define JUMPBACKWARDNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The JumpBackwardNode class is dedicated to change the previous dice of one dice option.
+ */
+class JumpBackwardNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief JumpBackwardNode allows to get result from remote node in the execution tree.
+ */
+ JumpBackwardNode();
+ /**
+ * @brief run - performs the actions
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief generateDotTree
+ * @param s
+ */
+ virtual void generateDotTree(QString& s);
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+ ExecutionNode* m_backwardNode;
+};
+
+#endif // JUMPBACKWARDNODE_H
diff --git a/src/libparser/node/keepdiceexecnode.cpp b/src/libparser/node/keepdiceexecnode.cpp
new file mode 100644
index 0000000..b197822
--- /dev/null
+++ b/src/libparser/node/keepdiceexecnode.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include <QList>
+
+#include "diceparser/parsingtoolbox.h"
+#include "keepdiceexecnode.h"
+
+KeepDiceExecNode::KeepDiceExecNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+KeepDiceExecNode::~KeepDiceExecNode() {}
+void KeepDiceExecNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous || nullptr == m_numberOfDiceNode)
+ {
+ return;
+ }
+ m_numberOfDiceNode->run(previous);
+ auto lastnode= ParsingToolBox::getLeafNode(m_numberOfDiceNode);
+ if(nullptr == lastnode)
+ return;
+ auto result= lastnode->getResult();
+ if(nullptr == result)
+ return;
+ if(!result->hasResultOfType(Dice::RESULT_TYPE::SCALAR))
+ return;
+
+ auto numberOfDice= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previousDiceResult);
+ if(nullptr != previousDiceResult)
+ {
+ QList<Die*> diceList= previousDiceResult->getResultList();
+
+ if(numberOfDice < 0)
+ {
+ numberOfDice= diceList.size() + numberOfDice;
+ }
+
+ QList<Die*> diceList3= diceList.mid(0, static_cast<int>(numberOfDice));
+ QList<Die*> diceList2;
+
+ for(Die* die : qAsConst(diceList3))
+ {
+ Die* tmpdie= new Die(*die);
+ diceList2.append(tmpdie);
+ die->displayed();
+ die->setSelected(false);
+ }
+
+ if(numberOfDice > static_cast<qint64>(diceList.size()))
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr(" You ask to keep %1 dice but the result only has %2")
+ .arg(numberOfDice)
+ .arg(diceList.size()));
+ }
+
+ for(auto& tmp : diceList.mid(static_cast<int>(numberOfDice), -1))
+ {
+ tmp->setHighlighted(false);
+ }
+
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+}
+
+void KeepDiceExecNode::setDiceKeepNumber(ExecutionNode* n)
+{
+ m_numberOfDiceNode= n;
+}
+QString KeepDiceExecNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ // auto param= m_numberOfDiceNode->toString(wl);
+ return QString("%1 [label=\"KeepDiceExecNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 KeepDiceExecNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* KeepDiceExecNode::getCopy() const
+{
+ KeepDiceExecNode* node= new KeepDiceExecNode();
+ if(nullptr != m_numberOfDiceNode)
+ {
+ node->setDiceKeepNumber(m_numberOfDiceNode->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/keepdiceexecnode.h b/src/libparser/node/keepdiceexecnode.h
new file mode 100644
index 0000000..0dd6616
--- /dev/null
+++ b/src/libparser/node/keepdiceexecnode.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef KEEPDICEEXECNODE_H
+#define KEEPDICEEXECNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The KeepDiceExecNode class splits the dice result to get the m_numberOfDice dice from the beginning of the
+ * dice result. Usually the pervious node of an KeepDiceExecNode is an SortNode.
+ */
+class KeepDiceExecNode : public ExecutionNode
+{
+public:
+ KeepDiceExecNode();
+ virtual ~KeepDiceExecNode();
+
+ virtual void run(ExecutionNode* previous);
+ virtual void setDiceKeepNumber(ExecutionNode* valueNode );
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ ExecutionNode* m_numberOfDiceNode = nullptr;
+ DiceResult* m_diceResult;
+};
+
+#endif // KEEPDICEEXECNODE_H
diff --git a/src/libparser/node/listaliasnode.cpp b/src/libparser/node/listaliasnode.cpp
new file mode 100644
index 0000000..c3f6d31
--- /dev/null
+++ b/src/libparser/node/listaliasnode.cpp
@@ -0,0 +1,85 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "listaliasnode.h"
+
+ListAliasNode::ListAliasNode(const QList<DiceAlias*>& apAlias) : m_aliasList(apAlias)
+{
+ m_result= new StringResult();
+}
+void ListAliasNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ StringResult* txtResult= dynamic_cast<StringResult*>(m_result);
+ txtResult->setHighLight(false);
+
+ txtResult->addText(buildList());
+ txtResult->finished();
+ if(nullptr != previous)
+ {
+ // txtResult->setText(previous->getHelp());
+ m_result->setPrevious(previous->getResult());
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString ListAliasNode::buildList() const
+{
+ QString result(QObject::tr("List of Alias:\n"));
+ for(auto& key : m_aliasList)
+ {
+ result+= QString("%1 : %2 # %3\n").arg(key->pattern(), key->command(), key->comment());
+ }
+ return result;
+}
+QString ListAliasNode::toString(bool wl) const
+{
+ QStringList resultList;
+ for(auto& key : m_aliasList)
+ {
+ resultList << "{" << key->pattern() << key->command() << "}";
+ }
+
+ if(wl)
+ {
+ return QString("%1 [label=\"ListAliasNode %2\"]").arg(m_id, resultList.join(","));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ListAliasNode::getPriority() const
+{
+ return 0;
+}
+
+ExecutionNode* ListAliasNode::getCopy() const
+{
+ ListAliasNode* node= new ListAliasNode(m_aliasList);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/listaliasnode.h b/src/libparser/node/listaliasnode.h
new file mode 100644
index 0000000..2a6f96e
--- /dev/null
+++ b/src/libparser/node/listaliasnode.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef LISTALIASNODE_H
+#define LISTALIASNODE_H
+
+#include <diceparser/dicealias.h>
+
+#include "executionnode.h"
+#include "result/stringresult.h"
+
+/**
+ * @brief The ListAliasNode class is dedicated to display the list of the current aliases.
+ */
+class ListAliasNode : public ExecutionNode
+{
+public:
+ ListAliasNode(const QList<DiceAlias*>& mapAlias);
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief buildList
+ * @return
+ */
+ virtual QString buildList() const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ const QList<DiceAlias*>& m_aliasList;
+};
+
+#endif // LISTALIASNODE_H
diff --git a/src/libparser/node/listsetrollnode.cpp b/src/libparser/node/listsetrollnode.cpp
new file mode 100644
index 0000000..2cee645
--- /dev/null
+++ b/src/libparser/node/listsetrollnode.cpp
@@ -0,0 +1,190 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#include "listsetrollnode.h"
+#include "die.h"
+
+#include <QDebug>
+
+ListSetRollNode::ListSetRollNode() : m_diceResult(new DiceResult()), m_stringResult(new StringResult()), m_unique(false)
+{
+ m_result= m_stringResult;
+}
+ListSetRollNode::~ListSetRollNode()
+{
+ if(nullptr != m_diceResult)
+ {
+ delete m_diceResult;
+ m_diceResult= nullptr;
+ }
+}
+
+QStringList ListSetRollNode::getList() const
+{
+ return m_values;
+}
+QString ListSetRollNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"ListSetRoll list:%2\"]").arg(m_id, m_values.join(","));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ListSetRollNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
+void ListSetRollNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ Result* result= previous->getResult();
+ if(nullptr != result)
+ {
+ quint64 diceCount= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ if(diceCount > static_cast<quint64>(m_values.size()) && m_unique)
+ {
+ m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE,
+ QObject::tr("More unique values asked than possible values (L operator)"));
+ }
+ else
+ {
+ m_result->setPrevious(result);
+ for(quint64 i= 0; i < diceCount; ++i)
+ {
+ QStringList rollResult;
+ Die* die= new Die();
+ computeFacesNumber(die);
+ die->roll();
+ m_diceResult->insertResult(die);
+ getValueFromDie(die, rollResult);
+ for(auto const& str : qAsConst(rollResult))
+ {
+ m_stringResult->addText(str);
+ }
+ }
+ m_stringResult->finished();
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+void ListSetRollNode::setListValue(QStringList lirs)
+{
+ m_values= lirs;
+}
+void ListSetRollNode::setUnique(bool u)
+{
+ m_unique= u;
+}
+void ListSetRollNode::setNoComma(bool b)
+{
+ if(m_stringResult)
+ m_stringResult->setNoComma(b);
+}
+void ListSetRollNode::setRangeList(QList<Range>& ranges)
+{
+ m_rangeList= ranges;
+}
+void ListSetRollNode::computeFacesNumber(Die* die)
+{
+ if(m_rangeList.isEmpty())
+ {
+ die->setMaxValue(m_values.size());
+ }
+ else
+ {
+ Q_ASSERT(m_values.size() == m_rangeList.size());
+ qint64 max;
+ int i= 0;
+ for(Range& range : m_rangeList)
+ {
+ if(((i == 0) || (max < range.getEnd())) && (range.isFullyDefined()))
+ {
+ max= range.getEnd();
+ }
+ ++i;
+ }
+ die->setMaxValue(max);
+ }
+}
+void ListSetRollNode::getValueFromDie(Die* die, QStringList& rollResult)
+{
+ if(m_rangeList.isEmpty())
+ {
+ if(die->getValue() - 1 < m_values.size())
+ {
+ auto str= m_values[die->getValue() - 1];
+ while(m_unique && rollResult.contains(str))
+ {
+ die->roll(false);
+ str= m_values[die->getValue() - 1];
+ }
+ rollResult << str;
+ }
+ }
+ else
+ {
+ Q_ASSERT(m_values.size() == m_rangeList.size());
+ bool found= false;
+ while(!found)
+ {
+ int i= 0;
+ for(Range& range : m_rangeList)
+ {
+ auto it= std::find(m_rangeIndexResult.begin(), m_rangeIndexResult.end(), i);
+ auto isValid= range.hasValid(die, false);
+ if((isValid && !m_unique) || (isValid && it == m_rangeIndexResult.end()))
+ {
+ m_rangeIndexResult.push_back(i);
+ rollResult << m_values[i];
+ found= true;
+ }
+ ++i;
+ }
+ if(!found)
+ {
+ die->roll(false);
+ }
+ }
+ }
+}
+ExecutionNode* ListSetRollNode::getCopy() const
+{
+ ListSetRollNode* node= new ListSetRollNode();
+ QList<Range> dataList= m_rangeList;
+ node->setRangeList(dataList);
+ node->setUnique(m_unique);
+ node->setListValue(m_values);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/listsetrollnode.h b/src/libparser/node/listsetrollnode.h
new file mode 100644
index 0000000..a6c5e1a
--- /dev/null
+++ b/src/libparser/node/listsetrollnode.h
@@ -0,0 +1,62 @@
+/*************************************************************************
+ * Copyright (C) 2009 by Renaud Guezennec *
+ * *
+ * https://rolisteam.org/ *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, *
+ * or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ *************************************************************************/
+#ifndef LISTSETROLLNODE_H
+#define LISTSETROLLNODE_H
+
+#include <QStringList>
+
+#include "executionnode.h"
+#include "range.h"
+#include "result/diceresult.h"
+#include "result/stringresult.h"
+/**
+ * @brief The ListSetRollNode class is dedicated to pick up item from list.
+ */
+class ListSetRollNode : public ExecutionNode
+{
+public:
+ ListSetRollNode();
+ virtual ~ListSetRollNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ QStringList getList() const;
+
+ void setListValue(QStringList);
+ void setUnique(bool);
+ void setNoComma(bool);
+ void setRangeList(QList<Range>&);
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ void getValueFromDie(Die* die, QStringList& rollResult);
+ void computeFacesNumber(Die* die);
+
+private:
+ QStringList m_values;
+ DiceResult* m_diceResult;
+ StringResult* m_stringResult;
+ std::vector<int> m_rangeIndexResult;
+ bool m_unique;
+ QList<Range> m_rangeList;
+};
+
+#endif // LISTSETROLLNODE_H
diff --git a/src/libparser/node/mergenode.cpp b/src/libparser/node/mergenode.cpp
new file mode 100644
index 0000000..096bb8c
--- /dev/null
+++ b/src/libparser/node/mergenode.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "mergenode.h"
+
+#include <diceparser/parsingtoolbox.h>
+
+MergeNode::MergeNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void MergeNode::run(ExecutionNode* previous)
+{
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Merge operator"));
+ return;
+ }
+
+ m_previousNode= previous;
+ m_result->setPrevious(previous->getResult());
+ ExecutionNode* previousLast= nullptr;
+ std::vector<Result*> pastResult;
+ for(auto start : *m_startList)
+ {
+ ExecutionNode* last= getLatestNode(start);
+ if(nullptr == last || nullptr == previousLast)
+ {
+ previousLast= last;
+ continue;
+ }
+
+ auto startResult= start->getResult();
+ if(nullptr == startResult)
+ continue;
+
+ startResult->setPrevious(previousLast->getResult());
+ previousLast->setNextNode(start);
+
+ previousLast= last;
+ Result* tmpResult= last->getResult();
+ while(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ ///@todo TODO improve here to set homogeneous while is really
+ m_diceResult->setHomogeneous(false);
+ for(auto& die : dice->getResultList())
+ {
+ if(!m_diceResult->getResultList().contains(die) && (!die->hasBeenDisplayed()))
+ {
+ Die* tmpdie= new Die(*die);
+ die->displayed();
+ m_diceResult->getResultList().append(tmpdie);
+ }
+ }
+ }
+ auto it= std::find_if(pastResult.begin(), pastResult.end(),
+ [tmpResult](const Result* a) { return (a == tmpResult->getPrevious()); });
+ if(it == pastResult.end())
+ {
+ pastResult.push_back(previousLast->getResult());
+ tmpResult= tmpResult->getPrevious();
+ }
+ else
+ {
+ tmpResult->setPrevious(nullptr);
+ tmpResult= nullptr;
+ }
+ }
+ }
+
+ auto first= m_startList->front();
+ m_startList->clear();
+ m_startList->push_back(first);
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+#include <QDebug>
+ExecutionNode* MergeNode::getLatestNode(ExecutionNode* node)
+{
+ ExecutionNode* next= node;
+ while(nullptr != next->getNextNode() && (next->getNextNode() != this))
+ {
+ // qDebug() << "find latest node" << next->toString(true) << next->getNextNode()->toString(true);
+ next= next->getNextNode();
+ }
+ return next;
+}
+QString MergeNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"Merge Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 MergeNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* MergeNode::getCopy() const
+{
+ MergeNode* node= new MergeNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+std::vector<ExecutionNode*>* MergeNode::getStartList() const
+{
+ return m_startList;
+}
+
+void MergeNode::setStartList(std::vector<ExecutionNode*>* startList)
+{
+ m_startList= startList;
+}
diff --git a/src/libparser/node/mergenode.h b/src/libparser/node/mergenode.h
new file mode 100644
index 0000000..515a2e9
--- /dev/null
+++ b/src/libparser/node/mergenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef MERGENODE_H
+#define MERGENODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The MergeNode class is an ExecutionNode. It is dedicated to merge result of several commands.
+ */
+class MergeNode : public ExecutionNode
+{
+public:
+ MergeNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ std::vector<ExecutionNode*>* getStartList() const;
+ void setStartList(std::vector<ExecutionNode*>* startList);
+
+private:
+ ExecutionNode* getLatestNode(ExecutionNode* node);
+
+private:
+ DiceResult* m_diceResult= nullptr;
+ std::vector<ExecutionNode*>* m_startList= nullptr;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/node.pri b/src/libparser/node/node.pri
new file mode 100644
index 0000000..6cf7005
--- /dev/null
+++ b/src/libparser/node/node.pri
@@ -0,0 +1,33 @@
+HEADERS += \
+ $$PWD/dicerollernode.h \
+ $$PWD/executionnode.h \
+ $$PWD/rerolldicenode.h \
+ $$PWD/startingnode.h \
+ $$PWD/scalaroperatornode.h \
+ $$PWD/numbernode.h \
+ $$PWD/sortresult.h \
+ $$PWD/keepdiceexecnode.h \
+ $$PWD/countexecutenode.h \
+ $$PWD/explodedicenode.h \
+ $$PWD/parenthesesnode.h \
+ $$PWD/helpnode.h \
+ $$PWD/jumpbackwardnode.h \
+ $$PWD/listsetrollnode.h\
+ $$PWD/listaliasnode.h
+
+SOURCES += \
+ $$PWD/dicerollernode.cpp \
+ $$PWD/executionnode.cpp \
+ $$PWD/startingnode.cpp \
+ $$PWD/rerolldicenode.cpp \
+ $$PWD/scalaroperatornode.cpp \
+ $$PWD/numbernode.cpp \
+ $$PWD/sortresult.cpp \
+ $$PWD/keepdiceexecnode.cpp \
+ $$PWD/countexecutenode.cpp \
+ $$PWD/explodedicenode.cpp \
+ $$PWD/parenthesesnode.cpp \
+ $$PWD/helpnode.cpp \
+ $$PWD/jumpbackwardnode.cpp \
+ $$PWD/listsetrollnode.cpp\
+ $$PWD/listaliasnode.cpp
diff --git a/src/libparser/node/numbernode.cpp b/src/libparser/node/numbernode.cpp
new file mode 100644
index 0000000..e50656e
--- /dev/null
+++ b/src/libparser/node/numbernode.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "numbernode.h"
+
+NumberNode::NumberNode() : m_scalarResult(new ScalarResult())
+{
+ m_result= m_scalarResult;
+}
+NumberNode::~NumberNode()
+{
+ /*if( nullptr != m_scalarResult)
+ {
+ delete m_scalarResult;
+ m_scalarResult = nullptr;
+ }*/
+}
+
+void NumberNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void NumberNode::setNumber(qint64 a)
+{
+ m_scalarResult->setValue(a);
+ m_number= a;
+}
+QString NumberNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"NumberNode %2\"]").arg(m_id).arg(m_number);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 NumberNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* NumberNode::getCopy() const
+{
+ NumberNode* node= new NumberNode();
+ node->setNumber(m_number);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/numbernode.h b/src/libparser/node/numbernode.h
new file mode 100644
index 0000000..02df984
--- /dev/null
+++ b/src/libparser/node/numbernode.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef NUMBERNODE_H
+#define NUMBERNODE_H
+
+#include "node/executionnode.h"
+#include "result/scalarresult.h"
+
+/**
+ * @brief The NumberNode class is an ExecutionNode. It is dedicated to store number.
+ */
+class NumberNode : public ExecutionNode
+{
+public:
+ NumberNode();
+ virtual ~NumberNode();
+ void run(ExecutionNode* previous);
+ void setNumber(qint64);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ qint64 m_number;
+ ScalarResult* m_scalarResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/occurencecountnode.cpp b/src/libparser/node/occurencecountnode.cpp
new file mode 100644
index 0000000..fc5c2f2
--- /dev/null
+++ b/src/libparser/node/occurencecountnode.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "occurencecountnode.h"
+#include "result/diceresult.h"
+#include "result/stringresult.h"
+#include "validatorlist.h"
+#include <QVector>
+
+OccurenceCountNode::OccurenceCountNode() : ExecutionNode() {}
+
+void OccurenceCountNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ std::map<qint64, qint64> mapOccurence;
+ if(nullptr == m_previousNode)
+ return;
+
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(m_previousNode->getResult());
+ if(nullptr == previousDiceResult)
+ return;
+
+ auto const& diceList= previousDiceResult->getResultList();
+ QVector<qint64> vec;
+
+ for(auto dice : diceList)
+ {
+ auto val= dice->getValue();
+
+ vec << val;
+ auto it= mapOccurence.find(val);
+ if(it == mapOccurence.end())
+ mapOccurence[val]= 1;
+ else
+ mapOccurence[val]+= 1;
+ }
+
+ std::sort(vec.begin(), vec.end());
+ if(nullptr == m_nextNode)
+ {
+ runForStringResult(mapOccurence, vec);
+ }
+ else
+ {
+ runForDiceResult(mapOccurence);
+ }
+}
+QString OccurenceCountNode::toString(bool label) const
+{
+ if(label)
+ {
+ return QString("%1 [label=\"OccurenceCountNode %2\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+ExecutionNode* OccurenceCountNode::getCopy() const
+{
+ return nullptr;
+}
+qint64 OccurenceCountNode::getPriority() const
+{
+ qint64 priority= 0;
+
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+qint64 OccurenceCountNode::getWidth() const
+{
+ return m_width;
+}
+
+void OccurenceCountNode::setWidth(const qint64& width)
+{
+ m_width= width;
+}
+
+qint64 OccurenceCountNode::getHeight() const
+{
+ return m_height;
+}
+
+void OccurenceCountNode::setHeight(const qint64& height)
+{
+ m_height= height;
+}
+
+ValidatorList* OccurenceCountNode::getValidatorList() const
+{
+ return m_validatorList;
+}
+
+void OccurenceCountNode::setValidatorList(ValidatorList* validatorlist)
+{
+ m_validatorList= validatorlist;
+}
+void OccurenceCountNode::runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec)
+{
+ m_stringResult= new StringResult();
+ m_result= m_stringResult;
+ QStringList list;
+ for(auto key : mapOccurence)
+ {
+ if(nullptr != m_validatorList)
+ {
+ Die die;
+ die.insertRollValue(key.first);
+ if(!m_validatorList->hasValid(&die, true))
+ continue;
+ }
+
+ if(key.second < m_width)
+ continue;
+
+ if(key.first >= m_height)
+ list << QStringLiteral("%1x%2").arg(key.second).arg(key.first);
+ }
+
+ QStringList resultList;
+ std::for_each(vec.begin(), vec.end(), [&resultList](qint64 val) { resultList << QString::number(val); });
+
+ QString result;
+
+ if(!list.isEmpty())
+ result= list.join(',');
+ else
+ result= QObject::tr("No matching result");
+
+ m_stringResult->addText(QStringLiteral("%1 - [%2]").arg(result).arg(resultList.join(',')));
+ m_stringResult->finished();
+}
+void OccurenceCountNode::runForDiceResult(const std::map<qint64, qint64>& mapOccurence)
+{
+ m_diceResult= new DiceResult();
+ m_result= m_diceResult;
+ QStringList list;
+ for(auto key : mapOccurence)
+ {
+ if(nullptr != m_validatorList)
+ {
+ Die die;
+ die.insertRollValue(key.first);
+ if(!m_validatorList->hasValid(&die, true))
+ continue;
+ }
+
+ if(key.second < m_width)
+ continue;
+
+ if(key.first >= m_height)
+ {
+ // list << QStringLiteral("%1x%2").arg(key.second).arg(key.first);
+ Die* die= new Die();
+ die->insertRollValue(key.second * key.first);
+ m_diceResult->insertResult(die);
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
diff --git a/src/libparser/node/occurencecountnode.h b/src/libparser/node/occurencecountnode.h
new file mode 100644
index 0000000..4801bfb
--- /dev/null
+++ b/src/libparser/node/occurencecountnode.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef OCCURENCECOUNTNODE_H
+#define OCCURENCECOUNTNODE_H
+
+#include "executionnode.h"
+
+class ValidatorList;
+class StringResult;
+class DiceResult;
+class OccurenceCountNode : public ExecutionNode
+{
+public:
+ OccurenceCountNode();
+
+ void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool withLabel) const;
+
+ ExecutionNode* getCopy() const;
+ qint64 getPriority() const;
+
+ qint64 getWidth() const;
+ void setWidth(const qint64& width);
+
+ qint64 getHeight() const;
+ void setHeight(const qint64& height);
+
+ ValidatorList* getValidatorList() const;
+ void setValidatorList(ValidatorList* validator);
+
+private:
+ void runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec);
+ void runForDiceResult(const std::map<qint64, qint64>& mapOccurence);
+
+private:
+ qint64 m_width= 1;
+ qint64 m_height= 0;
+ ValidatorList* m_validatorList= nullptr;
+ StringResult* m_stringResult= nullptr;
+ DiceResult* m_diceResult= nullptr;
+};
+
+#endif // OCCURENCECOUNTNODE_H
diff --git a/src/libparser/node/paintnode.cpp b/src/libparser/node/paintnode.cpp
new file mode 100644
index 0000000..22c020e
--- /dev/null
+++ b/src/libparser/node/paintnode.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "paintnode.h"
+
+ColorItem::ColorItem(QString str, int val) : m_colorNumber(val), m_color(str) {}
+
+int ColorItem::colorNumber() const
+{
+ return m_colorNumber;
+}
+
+void ColorItem::setColorNumber(int colorNumber)
+{
+ m_colorNumber= colorNumber;
+}
+
+QString ColorItem::color() const
+{
+ return m_color;
+}
+
+void ColorItem::setColor(const QString& color)
+{
+ m_color= color;
+}
+
+///////////////////////////////////
+/// @brief PainterNode::PainterNode
+///////////////////////////////////
+
+PainterNode::PainterNode() : ExecutionNode()
+{
+ m_nextNode= nullptr;
+}
+
+PainterNode::~PainterNode()
+{
+ m_result= nullptr;
+}
+
+void PainterNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Paint operator"));
+ return;
+ }
+ Result* previousResult= previous->getResult();
+ if(nullptr == previousResult)
+ return;
+
+ m_diceResult= dynamic_cast<DiceResult*>(previousResult->getCopy());
+ if(nullptr != m_diceResult)
+ {
+ QList<Die*> diceList= m_diceResult->getResultList();
+ int pastDice= 0;
+ for(ColorItem& item : m_colors)
+ {
+ int current= item.colorNumber();
+ QList<Die*>::iterator it;
+ for(it= diceList.begin() + pastDice; it != diceList.end() && current > 0; ++it)
+ {
+ (*it)->setColor(item.color());
+ --current;
+ ++pastDice;
+ }
+ }
+ m_diceResult->setPrevious(previousResult);
+ m_result= m_diceResult;
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString PainterNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"PainterNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 PainterNode::getPriority() const
+{
+ return 4;
+}
+
+void PainterNode::insertColorItem(QString color, int value)
+{
+ ColorItem item(color, value);
+ m_colors.append(item);
+}
+ExecutionNode* PainterNode::getCopy() const
+{
+ PainterNode* node= new PainterNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/paintnode.h b/src/libparser/node/paintnode.h
new file mode 100644
index 0000000..06d849e
--- /dev/null
+++ b/src/libparser/node/paintnode.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * http:://www.rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PAINTERNODE_H
+#define PAINTERNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+#include <QString>
+
+class ColorItem
+{
+public:
+ ColorItem(QString str, int val);
+ int colorNumber() const;
+ void setColorNumber(int colorNumber);
+
+ QString color() const;
+ void setColor(const QString& color);
+
+private:
+ int m_colorNumber;
+ QString m_color;
+};
+/**
+ * @brief The PainterNode class means to manage color attribute of dice.
+ */
+class PainterNode : public ExecutionNode
+{
+public:
+ PainterNode();
+ virtual ~PainterNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ void insertColorItem(QString color, int value);
+ virtual ExecutionNode* getCopy() const;
+
+protected:
+ QList<ColorItem> m_colors;
+ DiceResult* m_diceResult= nullptr;
+};
+
+#endif
diff --git a/src/libparser/node/parenthesesnode.cpp b/src/libparser/node/parenthesesnode.cpp
new file mode 100644
index 0000000..9557536
--- /dev/null
+++ b/src/libparser/node/parenthesesnode.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "parenthesesnode.h"
+
+ParenthesesNode::ParenthesesNode() : m_internalNode(nullptr) {}
+void ParenthesesNode::setInternelNode(ExecutionNode* node)
+{
+ m_internalNode= node;
+}
+void ParenthesesNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != m_internalNode)
+ {
+ m_internalNode->run(this);
+ ExecutionNode* temp= m_internalNode;
+ while(nullptr != temp->getNextNode())
+ {
+ temp= temp->getNextNode();
+ }
+ m_result= temp->getResult();
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString ParenthesesNode::toString(bool b) const
+{
+ if(b)
+ {
+ return QString("%1 [label=\"ParenthesesNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ParenthesesNode::getPriority() const
+{
+ qint64 priority= 3;
+ return priority;
+}
+ExecutionNode* ParenthesesNode::getCopy() const
+{
+ ParenthesesNode* node= new ParenthesesNode();
+ if(nullptr != m_internalNode)
+ {
+ node->setInternelNode(m_internalNode->getCopy());
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void ParenthesesNode::generateDotTree(QString& s)
+{
+ auto str= toString(true);
+ if(s.contains(str))
+ return;
+ s.append(str);
+ s.append(";\n");
+
+ if(nullptr != m_internalNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_internalNode->toString(false));
+ s.append("[label=\"internal\"];\n");
+ m_internalNode->generateDotTree(s);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append(" [label=\"next\"];\n");
+ // s.append(" [label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr;\n");
+ }
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+}
diff --git a/src/libparser/node/parenthesesnode.h b/src/libparser/node/parenthesesnode.h
new file mode 100644
index 0000000..153dfc1
--- /dev/null
+++ b/src/libparser/node/parenthesesnode.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PARENTHESESNODE_H
+#define PARENTHESESNODE_H
+
+#include "executionnode.h"
+/**
+ * @brief The ParenthesesNode class is an ExecutionNode. It is dedicated to manage expression which was inside
+ * ParenthesesNode. It is acting just like an StartingNode by for an internal execution tree.
+ */
+class ParenthesesNode : public ExecutionNode
+{
+public:
+ ParenthesesNode();
+ virtual void run(ExecutionNode* previous= nullptr);
+
+ void setInternelNode(ExecutionNode* node);
+ virtual QString toString(bool) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+ virtual void generateDotTree(QString&);
+
+private:
+ ExecutionNode* m_internalNode;
+};
+
+#endif // PARENTHESESNODE_H
diff --git a/src/libparser/node/repeaternode.cpp b/src/libparser/node/repeaternode.cpp
new file mode 100644
index 0000000..f93a9fe
--- /dev/null
+++ b/src/libparser/node/repeaternode.cpp
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "node/repeaternode.h"
+
+#include "executionnode.h"
+#include "result/scalarresult.h"
+#include "result/stringresult.h"
+#include <QDebug>
+#include <diceparser/diceparserhelper.h>
+#include <diceparser/parsingtoolbox.h>
+
+using InstructionSet= std::vector<ExecutionNode*>;
+
+QStringList allFirstResultAsString(const InstructionSet& startingNodes, bool& hasAlias)
+{
+ ParsingToolBox parsingBox;
+ // QStringList allResult;
+ QStringList stringListResult;
+ for(auto node : startingNodes)
+ {
+ auto pair= parsingBox.hasResultOfType(Dice::RESULT_TYPE::STRING, node);
+ auto pairStr= parsingBox.hasResultOfType(Dice::RESULT_TYPE::SCALAR, node, true);
+ if(pair.first)
+ {
+ stringListResult << pair.second.toString();
+ hasAlias= true;
+ }
+ else if(pairStr.first)
+ {
+ stringListResult << QString::number(pairStr.second.toReal());
+ hasAlias= true;
+ }
+ }
+ return stringListResult;
+}
+
+std::vector<ExecutionNode*> makeCopy(std::vector<ExecutionNode*> cmds)
+{
+ std::vector<ExecutionNode*> copy;
+ std::transform(cmds.begin(), cmds.end(), std::back_inserter(copy),
+ [](ExecutionNode* node) { return node->getCopy(); });
+ return copy;
+}
+
+RepeaterNode::RepeaterNode() {}
+
+void RepeaterNode::run(ExecutionNode* previousNode)
+{
+ m_previousNode= previousNode;
+
+ if(nullptr == m_times || m_cmd.empty())
+ return;
+
+ m_times->run(this);
+ m_times= ParsingToolBox::getLeafNode(m_times);
+ auto times= m_times->getResult();
+ if(!times)
+ return;
+
+ std::vector<InstructionSet> m_startingNodes;
+ auto timeCount= times->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ auto cmd= makeCopy(m_cmd);
+ std::vector<Result*> resultVec;
+ for(int i= 0; i < timeCount; ++i)
+ {
+ m_startingNodes.push_back(cmd);
+ std::for_each(cmd.begin(), cmd.end(),
+ [this, &resultVec](ExecutionNode* node)
+ {
+ node->run(this);
+ auto end= ParsingToolBox::getLeafNode(node);
+ auto leafResult= end->getResult();
+
+ if(nullptr == leafResult)
+ return;
+
+ resultVec.push_back(leafResult);
+ });
+ cmd= makeCopy(m_cmd);
+ }
+ if(m_sumAll)
+ {
+ auto scalar= new ScalarResult();
+ qreal value= 0.0;
+ std::for_each(resultVec.begin(), resultVec.end(),
+ [&value](Result* result) { value+= result->getResult(Dice::RESULT_TYPE::SCALAR).toDouble(); });
+ scalar->setValue(value);
+ m_result= scalar;
+ }
+ else
+ {
+ auto string= new StringResult();
+
+ QStringList listOfStrResult;
+ for(auto instructions : m_startingNodes)
+ {
+ ParsingToolBox parsingBox;
+ parsingBox.setStartNodes(instructions);
+ auto finalString
+ = parsingBox.finalStringResult([](const QString& result, const QString&, bool) { return result; });
+ listOfStrResult << finalString;
+ }
+ if(!listOfStrResult.isEmpty())
+ string->addText(listOfStrResult.join('\n'));
+
+ m_result= string;
+
+ // qDebug().noquote() << listOfStrResult.join('\n');
+ }
+
+ if(nullptr != m_nextNode)
+ m_nextNode->run(this);
+}
+
+QString RepeaterNode::toString(bool withLabel) const
+{
+ return withLabel ? QStringLiteral("") : QStringLiteral("");
+}
+
+qint64 RepeaterNode::getPriority() const
+{
+ return 4;
+}
+
+ExecutionNode* RepeaterNode::getCopy() const
+{
+ return nullptr;
+}
+
+void RepeaterNode::setCommand(const std::vector<ExecutionNode*>& cmd)
+{
+ m_cmd= cmd;
+}
+
+void RepeaterNode::setTimeNode(ExecutionNode* time)
+{
+ m_times= time;
+}
+
+void RepeaterNode::setSumAll(bool b)
+{
+ m_sumAll= b;
+}
diff --git a/src/libparser/node/repeaternode.h b/src/libparser/node/repeaternode.h
new file mode 100644
index 0000000..fa1a50a
--- /dev/null
+++ b/src/libparser/node/repeaternode.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2019 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REPEATER_NODE_H
+#define REPEATER_NODE_H
+
+#include "node/executionnode.h"
+#include <memory>
+
+class RepeaterNode : public ExecutionNode
+{
+public:
+ RepeaterNode();
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+
+ virtual ExecutionNode* getCopy() const override;
+
+ void setCommand(const std::vector<ExecutionNode*>& node);
+ void setTimeNode(ExecutionNode* times);
+ void setSumAll(bool b);
+
+private:
+ std::vector<ExecutionNode*> m_cmd;
+ ExecutionNode* m_times= nullptr;
+ bool m_sumAll= false;
+};
+
+#endif // REPEATER_NODE_H
diff --git a/src/libparser/node/replacevaluenode.cpp b/src/libparser/node/replacevaluenode.cpp
new file mode 100644
index 0000000..c313fb0
--- /dev/null
+++ b/src/libparser/node/replacevaluenode.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "replacevaluenode.h"
+
+#include "diceresult.h"
+#include <QDebug>
+#include <diceparser/parsingtoolbox.h>
+
+ReplaceValueNode::ReplaceValueNode() : m_diceResult(new DiceResult)
+{
+ m_result= m_diceResult;
+}
+
+void ReplaceValueNode::setStopAtFirt(bool b)
+{
+ m_stopAtFirst= b;
+}
+
+void ReplaceValueNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR,
+ QStringLiteral("No previous node before Switch/Case operator"));
+ return;
+ }
+ auto previousResult= previous->getResult();
+ m_result->setPrevious(previousResult);
+
+ if(nullptr == previousResult
+ || (!previousResult->hasResultOfType(Dice::RESULT_TYPE::SCALAR)
+ && !previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QStringLiteral("No scalar or dice result before Switch/Case operator"));
+ return;
+ }
+
+ QList<Die*> dieList;
+ if(previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ auto diceResult= dynamic_cast<DiceResult*>(previousResult);
+ if(diceResult)
+ dieList.append(diceResult->getResultList());
+ }
+
+ for(auto die : dieList)
+ {
+ QStringList resultList;
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ if(info->validatorList)
+ {
+ auto res= info->validatorList->hasValid(die, false);
+ if(!res)
+ continue;
+ }
+ else if(!resultList.isEmpty())
+ break;
+
+ auto replaceValresult= info->node->getResult();
+ if(replaceValresult)
+ die->replaceLastValue(replaceValresult->getResult(Dice::RESULT_TYPE::SCALAR).toInt());
+ break;
+ }
+ m_diceResult->insertResult(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString ReplaceValueNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"ReplaceValueNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 ReplaceValueNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* ReplaceValueNode::getCopy() const
+{
+ ReplaceValueNode* node= new ReplaceValueNode();
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ node->insertCase(info->node, info->validatorList);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void ReplaceValueNode::insertCase(ExecutionNode* node, ValidatorList* validator)
+{
+ std::unique_ptr<Dice::CaseInfo> info(new Dice::CaseInfo{validator, node});
+ m_branchList.push_back(std::move(info));
+}
diff --git a/src/libparser/node/replacevaluenode.h b/src/libparser/node/replacevaluenode.h
new file mode 100644
index 0000000..36bdec2
--- /dev/null
+++ b/src/libparser/node/replacevaluenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef REPLACEVALUENODE_H
+#define REPLACEVALUENODE_H
+
+#include <memory>
+#include <vector>
+
+#include "executionnode.h"
+#include "validatorlist.h"
+
+class DiceResult;
+class ReplaceValueNode : public ExecutionNode
+{
+public:
+ ReplaceValueNode();
+ void setStopAtFirt(bool b);
+
+ void run(ExecutionNode* previous= nullptr) override;
+
+ QString toString(bool withLabel) const override;
+ qint64 getPriority() const override;
+ ExecutionNode* getCopy() const override;
+
+ void insertCase(ExecutionNode* node, ValidatorList* validator);
+
+private:
+ std::vector<std::unique_ptr<Dice::CaseInfo>> m_branchList;
+ DiceResult* m_diceResult= nullptr;
+ bool m_stopAtFirst= false;
+};
+
+#endif // REPLACEVALUENODE_H
diff --git a/src/libparser/node/rerolldicenode.cpp b/src/libparser/node/rerolldicenode.cpp
new file mode 100644
index 0000000..fd8c258
--- /dev/null
+++ b/src/libparser/node/rerolldicenode.cpp
@@ -0,0 +1,148 @@
+#include <diceparser/parsingtoolbox.h>
+
+#include "rerolldicenode.h"
+#include "validatorlist.h"
+#include <utility>
+
+RerollDiceNode::RerollDiceNode(bool reroll, bool addingMode)
+ : m_diceResult(new DiceResult()), m_validatorList(nullptr), m_reroll(reroll), m_adding(addingMode)
+{
+ m_result= m_diceResult;
+}
+RerollDiceNode::~RerollDiceNode()
+{
+ if(nullptr != m_validatorList)
+ {
+ delete m_validatorList;
+ m_validatorList= nullptr;
+ }
+}
+void RerollDiceNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != previous) && (nullptr != previous->getResult()))
+ {
+ DiceResult* previous_result= dynamic_cast<DiceResult*>(previous->getResult());
+ m_result->setPrevious(previous_result);
+ if(nullptr != previous_result)
+ {
+ for(auto& die : previous_result->getResultList())
+ {
+ Die* tmpdie= new Die(*die);
+ m_diceResult->insertResult(tmpdie);
+ die->displayed();
+ }
+ // m_diceResult->setResultList(list);
+
+ QList<Die*>& list= m_diceResult->getResultList();
+ QList<Die*> toRemove;
+
+ for(auto& die : list)
+ {
+ bool finished= false;
+ auto state= m_validatorList->isValidRangeSize(
+ std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue()));
+ if((Dice::CONDITION_STATE::ALWAYSTRUE == state && m_adding)
+ || (!m_reroll && !m_adding && state == Dice::CONDITION_STATE::UNREACHABLE))
+ {
+ m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition (%1) cause an endless loop with this dice: %2")
+ .arg(toString(true))
+ .arg(QStringLiteral("d[%1,%2]")
+ .arg(static_cast<int>(die->getBase()))
+ .arg(static_cast<int>(die->getMaxValue()))));
+ continue;
+ }
+ while(m_validatorList->hasValid(die, false) && !finished)
+ {
+ if(m_instruction != nullptr)
+ {
+ m_instruction->run(this);
+ auto lastNode= ParsingToolBox::getLeafNode(m_instruction);
+ if(lastNode != nullptr)
+ {
+ auto lastResult= dynamic_cast<DiceResult*>(lastNode->getResult());
+ if(lastResult != nullptr)
+ {
+ toRemove.append(die);
+ list.append(lastResult->getResultList());
+ lastResult->clear();
+ }
+ }
+ }
+ else
+ {
+ die->roll(m_adding);
+ }
+ if(m_reroll)
+ {
+ finished= true;
+ }
+ }
+ }
+
+ for(auto die : toRemove)
+ {
+ list.removeOne(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ else
+ {
+ m_errors.insert(
+ Dice::ERROR_CODE::DIE_RESULT_EXPECTED,
+ QObject::tr(
+ " The a operator expects dice result. Please check the documentation and fix your command."));
+ }
+ }
+}
+void RerollDiceNode::setValidatorList(ValidatorList* val)
+{
+ m_validatorList= val;
+}
+QString RerollDiceNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"RerollDiceNode validatior: %2\"]").arg(m_id, m_validatorList->toString());
+ }
+ else
+ {
+ return m_id;
+ }
+ // return QString("RerollDiceNode [label=\"RerollDiceNode validatior:%1\"");
+}
+qint64 RerollDiceNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+
+ return priority;
+}
+ExecutionNode* RerollDiceNode::getCopy() const
+{
+ RerollDiceNode* node= new RerollDiceNode(m_reroll, m_adding);
+ node->setValidatorList(m_validatorList);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+ExecutionNode* RerollDiceNode::getInstruction() const
+{
+ return m_instruction;
+}
+
+void RerollDiceNode::setInstruction(ExecutionNode* instruction)
+{
+ m_instruction= instruction;
+}
diff --git a/src/libparser/node/rerolldicenode.h b/src/libparser/node/rerolldicenode.h
new file mode 100644
index 0000000..68b732e
--- /dev/null
+++ b/src/libparser/node/rerolldicenode.h
@@ -0,0 +1,72 @@
+#ifndef REROLLDICENODE_H
+#define REROLLDICENODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValidatorList;
+/**
+ * @brief The RerollDiceNode class reroll dice given a condition and replace(or add) the result.
+ */
+class RerollDiceNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief The ReRollMode enum
+ */
+ enum ReRollMode
+ {
+ EQUAL,
+ LESSER,
+ GREATER
+ };
+ /**
+ * @brief RerollDiceNode
+ * @param reroll If true reroll the dice only once, otherwise until the condition is false
+ */
+ RerollDiceNode(bool reroll, bool addingMode);
+
+ /**
+ * @brief ~RerollDiceNode
+ */
+ virtual ~RerollDiceNode();
+ /**
+ * @brief run
+ * @param previous
+ */
+ virtual void run(ExecutionNode* previous);
+
+ /**
+ * @brief setValidator
+ */
+ virtual void setValidatorList(ValidatorList*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+ ExecutionNode* getInstruction() const;
+ void setInstruction(ExecutionNode* instruction);
+
+private:
+ DiceResult* m_diceResult= nullptr;
+ ValidatorList* m_validatorList= nullptr;
+ ExecutionNode* m_instruction= nullptr;
+
+ const bool m_reroll;
+ const bool m_adding;
+};
+
+#endif // REROLLDICENODE_H
diff --git a/src/libparser/node/scalaroperatornode.cpp b/src/libparser/node/scalaroperatornode.cpp
new file mode 100644
index 0000000..c1c4dc5
--- /dev/null
+++ b/src/libparser/node/scalaroperatornode.cpp
@@ -0,0 +1,286 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "scalaroperatornode.h"
+
+#include "result/diceresult.h"
+#include <QDebug>
+
+ScalarOperatorNode::ScalarOperatorNode()
+ : m_internalNode(nullptr), m_scalarResult(new ScalarResult()), m_arithmeticOperator(Dice::ArithmeticOperator::PLUS)
+{
+ m_result= m_scalarResult;
+}
+ScalarOperatorNode::~ScalarOperatorNode()
+{
+ if(nullptr != m_internalNode)
+ {
+ delete m_internalNode;
+ m_internalNode= nullptr;
+ }
+}
+
+void ScalarOperatorNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != m_internalNode)
+ {
+ m_internalNode->run(this);
+ }
+ if(nullptr != previous)
+ {
+ auto previousResult= previous->getResult();
+
+ if(nullptr != previousResult)
+ {
+ ExecutionNode* internal= m_internalNode;
+ if(nullptr != internal)
+ {
+ while(nullptr != internal->getNextNode())
+ {
+ internal= internal->getNextNode();
+ }
+
+ Result* internalResult= internal->getResult();
+ m_result->setPrevious(internalResult);
+ if(nullptr != m_internalNode->getResult())
+ {
+ m_internalNode->getResult()->setPrevious(previousResult);
+ }
+
+ if(internalResult == nullptr)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QObject::tr("No Valid result in arithmetic operation: %1").arg(toString(true)));
+ return;
+ }
+
+ switch(m_arithmeticOperator)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ m_scalarResult->setValue(add(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ m_scalarResult->setValue(substract(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ m_scalarResult->setValue(multiple(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::DIVIDE:
+ m_scalarResult->setValue(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ m_scalarResult->setValue(
+ static_cast<int>(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())));
+ break;
+ case Dice::ArithmeticOperator::POW:
+ m_scalarResult->setValue(pow(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(),
+ internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()));
+ break;
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ }
+}
+/*bool ScalarOperatorNode::setOperatorChar(QChar c)
+{
+ if(m_scalarOperationList.contains(c))
+ {
+ m_operator = m_scalarOperationList.value(c);
+ return true;
+ }
+ return false;
+}*/
+
+void ScalarOperatorNode::setInternalNode(ExecutionNode* node)
+{
+ m_internalNode= node;
+}
+qint64 ScalarOperatorNode::add(qreal a, qreal b)
+{
+ return static_cast<qint64>(a + b);
+}
+qint64 ScalarOperatorNode::substract(qreal a, qreal b)
+{
+ return static_cast<qint64>(a - b);
+}
+qreal ScalarOperatorNode::divide(qreal a, qreal b)
+{
+ if(qFuzzyCompare(b, 0))
+ {
+ m_errors.insert(Dice::ERROR_CODE::DIVIDE_BY_ZERO, QObject::tr("Division by zero"));
+ return 0;
+ }
+ return static_cast<qreal>(a / b);
+}
+qint64 ScalarOperatorNode::multiple(qreal a, qreal b)
+{
+ return static_cast<qint64>(a * b);
+}
+qint64 ScalarOperatorNode::pow(qreal a, qreal b)
+{
+ return static_cast<qint64>(std::pow(a, b));
+}
+Dice::ArithmeticOperator ScalarOperatorNode::getArithmeticOperator() const
+{
+ return m_arithmeticOperator;
+}
+
+void ScalarOperatorNode::setArithmeticOperator(const Dice::ArithmeticOperator& arithmeticOperator)
+{
+ m_arithmeticOperator= arithmeticOperator;
+}
+
+QString ScalarOperatorNode::toString(bool wl) const
+{
+ QString op= "";
+ switch(m_arithmeticOperator)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ op= "+";
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ op= "-";
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ op= "*";
+ break;
+ case Dice::ArithmeticOperator::DIVIDE:
+ op= "/";
+ break;
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ op= "|";
+ break;
+ case Dice::ArithmeticOperator::POW:
+ op= "^";
+ break;
+ }
+ if(wl)
+ {
+ return QString("%1 [label=\"ScalarOperatorNode %2\"]").arg(m_id, op);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ScalarOperatorNode::getPriority() const
+{
+ if((m_arithmeticOperator == Dice::ArithmeticOperator::PLUS)
+ || (m_arithmeticOperator == Dice::ArithmeticOperator::MINUS))
+ {
+ return 1;
+ }
+ else if(m_arithmeticOperator == Dice::ArithmeticOperator::POW)
+ {
+ return 3;
+ }
+ else
+ {
+ return 2;
+ }
+}
+void ScalarOperatorNode::generateDotTree(QString& s)
+{
+ auto id= toString(true);
+ if(s.contains(id))
+ return;
+ s.append(id);
+ s.append(";\n");
+
+ if(nullptr != m_nextNode)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_nextNode->toString(false));
+ s.append("[label=\"nextNode\"];\n");
+ m_nextNode->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr");
+ s.append(" [label=\"nextNode\"];\n");
+ }
+
+ if(nullptr != m_result)
+ {
+ s.append(toString(false));
+ s.append(" ->");
+ s.append(m_result->toString(false));
+ s.append(" [label=\"Result\", style=\"dashed\"];\n");
+ if(nullptr == m_nextNode)
+ m_result->generateDotTree(s);
+ }
+ QString str;
+ str.append("\n");
+ if(nullptr != m_internalNode)
+ {
+ str.append(toString(false));
+ str.append(" -> ");
+ str.append(m_internalNode->toString(false));
+ str.append(" [label=\"internalNode\"];\n");
+ m_internalNode->generateDotTree(str);
+ }
+ s.append(str);
+}
+QMap<Dice::ERROR_CODE, QString> ScalarOperatorNode::getExecutionErrorMap()
+{
+ if(nullptr != m_internalNode)
+ {
+ auto keys= m_internalNode->getExecutionErrorMap().keys();
+ for(const auto& key : keys)
+ {
+ m_errors.insert(key, m_internalNode->getExecutionErrorMap().value(key));
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ auto keys= m_nextNode->getExecutionErrorMap().keys();
+ for(auto const& key : keys)
+ {
+ m_errors.insert(key, m_nextNode->getExecutionErrorMap().value(key));
+ }
+ }
+ return m_errors;
+}
+ExecutionNode* ScalarOperatorNode::getCopy() const
+{
+ ScalarOperatorNode* node= new ScalarOperatorNode();
+ node->setInternalNode(m_internalNode->getCopy());
+ node->setArithmeticOperator(m_arithmeticOperator);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/scalaroperatornode.h b/src/libparser/node/scalaroperatornode.h
new file mode 100644
index 0000000..57a1049
--- /dev/null
+++ b/src/libparser/node/scalaroperatornode.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SCALAROPERATORNODE_H
+#define SCALAROPERATORNODE_H
+
+#include <QChar>
+#include <QMap>
+
+#include "die.h"
+#include "executionnode.h"
+#include "result/scalarresult.h"
+
+/**
+ * @brief The ScalarOperatorNode class
+ */
+class ScalarOperatorNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief The ArithmeticOperator enum
+ */
+ // enum ArithmeticOperator {PLUS,MINUS,DIVIDE,MULTIPLICATION};
+ /**
+ * @brief ScalarOperatorNode
+ */
+ ScalarOperatorNode();
+ /**
+ * @brief ~ScalarOperatorNode
+ */
+ virtual ~ScalarOperatorNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief setInternalNode
+ * @param node
+ */
+ void setInternalNode(ExecutionNode* node);
+ /**
+ * @brief toString
+ * @param wl
+ * @return
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief generateDotTree
+ * @param s
+ */
+ void generateDotTree(QString& s);
+ /**
+ * @brief getErrorList
+ * @return
+ */
+ virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap();
+ /**
+ * @brief getArithmeticOperator
+ * @return
+ */
+ Dice::ArithmeticOperator getArithmeticOperator() const;
+ /**
+ * @brief setArithmeticOperator
+ * @param arithmeticOperator
+ */
+ void setArithmeticOperator(const Dice::ArithmeticOperator& arithmeticOperator);
+
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ /**
+ * @brief add
+ * @return
+ */
+ static qint64 add(qreal, qreal);
+ /**
+ * @brief substract
+ * @return
+ */
+ static qint64 substract(qreal, qreal);
+ /**
+ * @brief divide not static because of error management
+ * @return
+ */
+ qreal divide(qreal, qreal);
+ /**
+ * @brief multiple
+ * @return
+ */
+ static qint64 multiple(qreal, qreal);
+
+ static qint64 pow(qreal a, qreal b);
+
+private:
+ ExecutionNode* m_internalNode;
+ ScalarResult* m_scalarResult;
+ Dice::ArithmeticOperator m_arithmeticOperator;
+};
+
+#endif // SCALAROPERATORNODE_H
diff --git a/src/libparser/node/sortresult.cpp b/src/libparser/node/sortresult.cpp
new file mode 100644
index 0000000..5d514cf
--- /dev/null
+++ b/src/libparser/node/sortresult.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "sortresult.h"
+
+#include "die.h"
+
+SortResultNode::SortResultNode() : m_diceResult(new DiceResult)
+{
+ m_ascending= true;
+ m_result= m_diceResult;
+}
+void SortResultNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ return;
+ }
+ DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult());
+ m_diceResult->setPrevious(previousDiceResult);
+ if(nullptr == previousDiceResult)
+ return;
+
+ auto const& diceList= previousDiceResult->getResultList();
+ QList<Die*> diceList2= m_diceResult->getResultList();
+
+ /* const auto& asce = [](const Die* a,const Die* b){
+ return a->getValue() < b->getValue();
+ };
+ const auto& desc = [](const Die* a,const Die* b){
+ return a->getValue() > b->getValue();
+ };
+
+ for(auto const dice : diceList)
+ {
+ Die* tmp1 = new Die(*dice);
+ diceList2.append(tmp1);
+ }
+ if(m_ascending)
+ std::sort(diceList2.begin(), diceList2.end(), asce);
+ else
+ std::sort(diceList2.begin(), diceList2.end(), desc);*/
+
+ // half-interval search sorting
+ for(int i= 0; i < diceList.size(); ++i)
+ {
+ Die* tmp1= new Die(*diceList[i]);
+ //qDebug() << tmp1->getColor() << diceList[i]->getColor();
+ //*tmp1=*diceList[i];
+ diceList[i]->displayed();
+
+ int j= 0;
+ bool found= false;
+ int start= 0;
+ int end= diceList2.size();
+ Die* tmp2= nullptr;
+ while(!found)
+ {
+ int distance= end - start;
+ j= (start + end) / 2;
+ if(distance == 0)
+ {
+ j= end;
+ found= true;
+ }
+ else
+ {
+ tmp2= diceList2[j];
+ if(tmp1->getValue() < tmp2->getValue())
+ {
+ end= j;
+ }
+ else
+ {
+ start= j + 1;
+ }
+ }
+ }
+ diceList2.insert(j, tmp1);
+ }
+
+ if(!m_ascending)
+ {
+ for(int i= 0; i < diceList2.size() / 2; ++i)
+ {
+ diceList2.swapItemsAt(i, diceList2.size() - (1 + i));
+ }
+ }
+ m_diceResult->setResultList(diceList2);
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+void SortResultNode::setSortAscending(bool asc)
+{
+ m_ascending= asc;
+}
+QString SortResultNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ auto order= m_ascending ? QStringLiteral("Ascending") : QStringLiteral("Descending");
+ return QString("%1 [label=\"SortResultNode %2\"]").arg(m_id, order);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 SortResultNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* SortResultNode::getCopy() const
+{
+ SortResultNode* node= new SortResultNode();
+ node->setSortAscending(m_ascending);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/sortresult.h b/src/libparser/node/sortresult.h
new file mode 100644
index 0000000..f7510be
--- /dev/null
+++ b/src/libparser/node/sortresult.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SORTRESULT_H
+#define SORTRESULT_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+/**
+ * @brief The SortResultNode class is an ExecutionNode, and it is dedicated to sort dice list.
+ * The sort is made by hand, using half-interval search algorithm.
+ */
+class SortResultNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief SortResultNode
+ */
+ SortResultNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+
+ /**
+ * @brief setSortAscending
+ * @param asc
+ */
+ void setSortAscending(bool asc);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool wl) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ bool m_ascending;
+ DiceResult* m_diceResult;
+};
+
+#endif // SORTRESULT_H
diff --git a/src/libparser/node/splitnode.cpp b/src/libparser/node/splitnode.cpp
new file mode 100644
index 0000000..8faa0a5
--- /dev/null
+++ b/src/libparser/node/splitnode.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "splitnode.h"
+
+SplitNode::SplitNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void SplitNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ for(auto& oldDie : dice->getResultList())
+ {
+ oldDie->displayed();
+ m_diceResult->setOperator(oldDie->getOp());
+ for(qint64& value : oldDie->getListValue())
+ {
+ Die* tmpdie= new Die();
+ tmpdie->insertRollValue(value);
+ tmpdie->setBase(oldDie->getBase());
+ tmpdie->setMaxValue(oldDie->getMaxValue());
+ tmpdie->setValue(value);
+ tmpdie->setOp(oldDie->getOp());
+ m_diceResult->insertResult(tmpdie);
+ }
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString SplitNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SplitNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 SplitNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* SplitNode::getCopy() const
+{
+ SplitNode* node= new SplitNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/splitnode.h b/src/libparser/node/splitnode.h
new file mode 100644
index 0000000..0ceeb00
--- /dev/null
+++ b/src/libparser/node/splitnode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SPLITNODE_H
+#define SPLITNODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The SplitNode class is an ExecutionNode. It is dedicated to split result of one dice into one dimension array.
+ */
+class SplitNode : public ExecutionNode
+{
+public:
+ SplitNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/startingnode.cpp b/src/libparser/node/startingnode.cpp
new file mode 100644
index 0000000..97248c6
--- /dev/null
+++ b/src/libparser/node/startingnode.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "startingnode.h"
+#include <QDebug>
+
+StartingNode::StartingNode() {}
+void StartingNode::run(ExecutionNode*)
+{
+ m_previousNode= nullptr;
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+QString StartingNode::toString(bool withlabel) const
+{
+ if(withlabel)
+ {
+ return QString("%1 [label=\"StartingNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 StartingNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* StartingNode::getCopy() const
+{
+ StartingNode* node= new StartingNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/startingnode.h b/src/libparser/node/startingnode.h
new file mode 100644
index 0000000..eea72a9
--- /dev/null
+++ b/src/libparser/node/startingnode.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef STARTINGNODE_H
+#define STARTINGNODE_H
+
+#include "executionnode.h"
+
+/**
+ * @brief The StartingNode class is an ExecutionNode, StartingNode is dedicated to be the first node
+ * in the execution tree.
+ */
+class StartingNode : public ExecutionNode
+{
+public:
+ /**
+ * @brief StartingNode
+ */
+ StartingNode();
+ /**
+ * @brief run
+ */
+ virtual void run(ExecutionNode*);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool withlabel) const;
+ /**
+ * @brief getPriority
+ * @return
+ */
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+};
+
+#endif // STARTINGNODE_H
diff --git a/src/libparser/node/stringnode.cpp b/src/libparser/node/stringnode.cpp
new file mode 100644
index 0000000..e908463
--- /dev/null
+++ b/src/libparser/node/stringnode.cpp
@@ -0,0 +1,58 @@
+#include "stringnode.h"
+
+StringNode::StringNode() : m_stringResult(new StringResult())
+{
+ m_result= m_stringResult;
+}
+
+void StringNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void StringNode::setString(QString str)
+{
+ m_data= str;
+ m_stringResult->addText(m_data);
+ m_stringResult->finished();
+}
+QString StringNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ QString dataCopy= m_data;
+
+ return QString("%1 [label=\"StringNode %2\"]").arg(m_id, dataCopy.replace('%', '\\'));
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 StringNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* StringNode::getCopy() const
+{
+ StringNode* node= new StringNode();
+ node->setString(m_data);
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/stringnode.h b/src/libparser/node/stringnode.h
new file mode 100644
index 0000000..4079b7f
--- /dev/null
+++ b/src/libparser/node/stringnode.h
@@ -0,0 +1,29 @@
+#ifndef STRINGNODE_H
+#define STRINGNODE_H
+
+#include "node/executionnode.h"
+#include "result/stringresult.h"
+
+/**
+ * @brief The StringNode class is an ExecutionNode. It is dedicated to store string and display result.
+ */
+class StringNode : public ExecutionNode
+{
+public:
+ StringNode();
+ void run(ExecutionNode* previous);
+ void setString(QString str);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ QString m_data;
+ StringResult* m_stringResult;
+};
+
+#endif // STRINGNODE_H
diff --git a/src/libparser/node/switchcasenode.cpp b/src/libparser/node/switchcasenode.cpp
new file mode 100644
index 0000000..880fa4d
--- /dev/null
+++ b/src/libparser/node/switchcasenode.cpp
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "switchcasenode.h"
+
+#include "stringresult.h"
+#include <QDebug>
+#include <diceparser/parsingtoolbox.h>
+
+SwitchCaseNode::SwitchCaseNode() : m_stringResult(new StringResult)
+{
+ m_result= m_stringResult;
+}
+
+void SwitchCaseNode::setStopAtFirt(bool b)
+{
+ m_stopAtFirst= b;
+}
+
+void SwitchCaseNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr == previous)
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR,
+ QStringLiteral("No previous node before Switch/Case operator"));
+ return;
+ }
+ auto previousResult= previous->getResult();
+ m_result->setPrevious(previousResult);
+
+ if(nullptr == previousResult
+ || (!previousResult->hasResultOfType(Dice::RESULT_TYPE::SCALAR)
+ && !previousResult->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)))
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT,
+ QStringLiteral("No scalar or dice result before Switch/Case operator"));
+ return;
+ }
+
+ auto diceResult= dynamic_cast<DiceResult*>(previousResult);
+
+ QSet<QString> alreadyValidDice;
+ QStringList finalResultList;
+ if(diceResult)
+ {
+ for(auto die : diceResult->getResultList())
+ {
+ QStringList resultList;
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ if(m_stopAtFirst && !resultList.isEmpty())
+ break;
+ if(info->validatorList)
+ {
+ if(info->validatorList->hasValid(die, true))
+ {
+ auto lastNode= ParsingToolBox::getLeafNode(info->node);
+ if(lastNode && lastNode->getResult())
+ {
+ resultList << lastNode->getResult()->getStringResult();
+ }
+ }
+ }
+ else if(resultList.isEmpty())
+ {
+ info->node->run(m_previousNode);
+ auto lastNode= ParsingToolBox::getLeafNode(info->node);
+ if(lastNode && lastNode->getResult())
+ {
+ resultList << lastNode->getResult()->getStringResult();
+ }
+ else
+ resultList << QString();
+ }
+ }
+ finalResultList << resultList;
+ }
+ }
+ for(auto const& str : qAsConst(finalResultList))
+ m_stringResult->addText(str);
+
+ if(m_stringResult->getText().isEmpty())
+ m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT, QStringLiteral("No value fits the Switch/Case operator"));
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString SwitchCaseNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"SwitchCaseNode\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 SwitchCaseNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* SwitchCaseNode::getCopy() const
+{
+ SwitchCaseNode* node= new SwitchCaseNode();
+ for(auto const& info : qAsConst(m_branchList))
+ {
+ node->insertCase(info->node, info->validatorList);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+void SwitchCaseNode::insertCase(ExecutionNode* node, ValidatorList* validator)
+{
+ std::unique_ptr<Dice::CaseInfo> info(new Dice::CaseInfo{validator, node});
+ m_branchList.push_back(std::move(info));
+}
diff --git a/src/libparser/node/switchcasenode.h b/src/libparser/node/switchcasenode.h
new file mode 100644
index 0000000..a0f658d
--- /dev/null
+++ b/src/libparser/node/switchcasenode.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This software is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SWITCHCASENODE_H
+#define SWITCHCASENODE_H
+
+#include <memory>
+#include <vector>
+
+#include "executionnode.h"
+#include "validatorlist.h"
+
+class StringResult;
+class SwitchCaseNode : public ExecutionNode
+{
+public:
+ SwitchCaseNode();
+ void setStopAtFirt(bool b);
+
+ void run(ExecutionNode* previous= nullptr) override;
+
+ QString toString(bool withLabel) const override;
+ qint64 getPriority() const override;
+ ExecutionNode* getCopy() const override;
+
+ void insertCase(ExecutionNode* node, ValidatorList* validator);
+
+private:
+ std::vector<std::unique_ptr<Dice::CaseInfo>> m_branchList;
+ StringResult* m_stringResult;
+ bool m_stopAtFirst= false;
+};
+
+#endif // SWITCHCASENODE_H
diff --git a/src/libparser/node/uniquenode.cpp b/src/libparser/node/uniquenode.cpp
new file mode 100644
index 0000000..c4668be
--- /dev/null
+++ b/src/libparser/node/uniquenode.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "uniquenode.h"
+
+UniqueNode::UniqueNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+void UniqueNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if(nullptr != previous)
+ {
+ m_result->setPrevious(previous->getResult());
+ Result* tmpResult= previous->getResult();
+ if(nullptr != tmpResult)
+ {
+ DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult);
+ if(nullptr != dice)
+ {
+ auto const& resultList= dice->getResultList();
+ std::vector<qint64> formerValues;
+ formerValues.reserve(resultList.size());
+ for(auto& oldDie : resultList)
+ {
+ auto value= oldDie->getValue();
+ auto it= std::find(formerValues.begin(), formerValues.end(), value);
+
+ if(it == formerValues.end())
+ {
+ auto die= new Die(*oldDie);
+ m_diceResult->insertResult(die);
+ formerValues.push_back(value);
+ }
+ oldDie->displayed();
+ }
+ }
+ }
+ }
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+QString UniqueNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"UniqueNode Node\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 UniqueNode::getPriority() const
+{
+ qint64 priority= 0;
+ if(nullptr != m_nextNode)
+ {
+ priority= m_nextNode->getPriority();
+ }
+ return priority;
+}
+ExecutionNode* UniqueNode::getCopy() const
+{
+ UniqueNode* node= new UniqueNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
diff --git a/src/libparser/node/uniquenode.h b/src/libparser/node/uniquenode.h
new file mode 100644
index 0000000..039ba11
--- /dev/null
+++ b/src/libparser/node/uniquenode.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef UNIQUENODE_H
+#define UNIQUENODE_H
+
+#include "node/executionnode.h"
+#include "result/diceresult.h"
+
+/**
+ * @brief The UniqueNode class is an ExecutionNode. It is dedicated to unique result of one dice into one dimension array.
+ */
+class UniqueNode : public ExecutionNode
+{
+public:
+ UniqueNode();
+ void run(ExecutionNode* previous);
+ virtual QString toString(bool withLabel) const;
+ virtual qint64 getPriority() const;
+ virtual ExecutionNode* getCopy() const;
+
+private:
+ DiceResult* m_diceResult;
+};
+
+#endif // NUMBERNODE_H
diff --git a/src/libparser/node/valueslistnode.cpp b/src/libparser/node/valueslistnode.cpp
new file mode 100644
index 0000000..33a347d
--- /dev/null
+++ b/src/libparser/node/valueslistnode.cpp
@@ -0,0 +1,62 @@
+#include "valueslistnode.h"
+
+#include "variablenode.h"
+
+ValuesListNode::ValuesListNode() : m_diceResult(new DiceResult())
+{
+ m_result= m_diceResult;
+}
+
+void ValuesListNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ for(auto node : m_data)
+ {
+ node->run(this);
+ auto result= node->getResult();
+ if(!result)
+ continue;
+ auto val= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ Die* die= new Die();
+ auto dyna= dynamic_cast<VariableNode*>(node);
+ if(nullptr != dyna)
+ dyna->setDisplayed();
+ die->insertRollValue(val);
+ m_diceResult->insertResult(die);
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+}
+
+void ValuesListNode::insertValue(ExecutionNode* value)
+{
+ m_data.push_back(value);
+}
+ExecutionNode* ValuesListNode::getCopy() const
+{
+ ValuesListNode* node= new ValuesListNode();
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+QString ValuesListNode::toString(bool wl) const
+{
+ if(wl)
+ {
+ return QString("%1 [label=\"ValuesListNode list:\"]").arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+qint64 ValuesListNode::getPriority() const
+{
+ qint64 priority= 4;
+ return priority;
+}
diff --git a/src/libparser/node/valueslistnode.h b/src/libparser/node/valueslistnode.h
new file mode 100644
index 0000000..100f275
--- /dev/null
+++ b/src/libparser/node/valueslistnode.h
@@ -0,0 +1,24 @@
+#ifndef VALUESLISTNODE_H
+#define VALUESLISTNODE_H
+
+#include "executionnode.h"
+#include "result/diceresult.h"
+
+class ValuesListNode : public ExecutionNode
+{
+public:
+ ValuesListNode();
+
+ virtual void run(ExecutionNode* previous= nullptr) override;
+ virtual QString toString(bool) const override;
+ virtual qint64 getPriority() const override;
+ virtual ExecutionNode* getCopy() const override;
+
+ void insertValue(ExecutionNode*);
+
+private:
+ std::vector<ExecutionNode*> m_data;
+ DiceResult* m_diceResult = nullptr;
+};
+
+#endif // VALUESLISTNODE_H
diff --git a/src/libparser/node/variablenode.cpp b/src/libparser/node/variablenode.cpp
new file mode 100644
index 0000000..709ab46
--- /dev/null
+++ b/src/libparser/node/variablenode.cpp
@@ -0,0 +1,112 @@
+#include "variablenode.h"
+
+#include "diceresult.h"
+#include <diceparser/parsingtoolbox.h>
+
+VariableNode::VariableNode() {}
+
+void VariableNode::run(ExecutionNode* previous)
+{
+ m_previousNode= previous;
+ if((nullptr != m_data) && (m_data->size() > m_index))
+ {
+ auto value= (*m_data)[m_index];
+ value= ParsingToolBox::getLeafNode(value);
+ if(nullptr == value)
+ return;
+
+ auto result= value->getResult();
+ if(!result)
+ return;
+
+ m_result= result->getCopy();
+ auto diceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != diceResult)
+ {
+ for(auto& die : diceResult->getResultList())
+ {
+ die->setDisplayed(false);
+ }
+ }
+
+ if(nullptr != m_nextNode)
+ {
+ m_nextNode->run(this);
+ }
+ }
+ else
+ {
+ m_errors.insert(Dice::ERROR_CODE::NO_VARIBALE, QObject::tr("No variable at index:%1").arg(m_index + 1));
+ }
+}
+
+void VariableNode::setDisplayed()
+{
+ if(!m_result)
+ return;
+ auto diceResult= dynamic_cast<DiceResult*>(m_result);
+ if(nullptr == diceResult)
+ return;
+
+ for(auto& die : diceResult->getResultList())
+ {
+ die->setDisplayed(true);
+ }
+}
+
+QString VariableNode::toString(bool withLabel) const
+{
+ if(withLabel)
+ {
+ return QString("%1 [label=\"VariableNode index: %2\"]").arg(m_id).arg(m_index + 1);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+
+qint64 VariableNode::getPriority() const
+{
+ qint64 priority= 4;
+ if(nullptr != m_previousNode)
+ {
+ priority= m_previousNode->getPriority();
+ }
+ return priority;
+}
+
+ExecutionNode* VariableNode::getCopy() const
+{
+ VariableNode* node= new VariableNode();
+ node->setIndex(m_index);
+ if(nullptr != m_data)
+ {
+ node->setData(m_data);
+ }
+ if(nullptr != m_nextNode)
+ {
+ node->setNextNode(m_nextNode->getCopy());
+ }
+ return node;
+}
+
+quint64 VariableNode::getIndex() const
+{
+ return m_index;
+}
+
+void VariableNode::setIndex(quint64 index)
+{
+ m_index= index;
+}
+
+std::vector<ExecutionNode*>* VariableNode::getData() const
+{
+ return m_data;
+}
+
+void VariableNode::setData(std::vector<ExecutionNode*>* data)
+{
+ m_data= data;
+}
diff --git a/src/libparser/node/variablenode.h b/src/libparser/node/variablenode.h
new file mode 100644
index 0000000..8bf1cb1
--- /dev/null
+++ b/src/libparser/node/variablenode.h
@@ -0,0 +1,35 @@
+#ifndef VARIABLENODE_H
+#define VARIABLENODE_H
+
+#include "node/executionnode.h"
+
+/**
+ * @brief The VariableNode class is an ExecutionNode. It is dedicated to retrive
+ * variable value from other starting node.
+ */
+class VariableNode : public ExecutionNode
+{
+public:
+ VariableNode();
+ void run(ExecutionNode* previous) override;
+ virtual QString toString(bool withLabel) const override;
+ virtual qint64 getPriority() const override;
+ /**
+ * @brief getCopy
+ * @return
+ */
+ virtual ExecutionNode* getCopy() const override;
+ quint64 getIndex() const;
+ void setIndex(quint64 index);
+
+ std::vector<ExecutionNode*>* getData() const;
+ void setData(std::vector<ExecutionNode*>* data);
+
+ void setDisplayed();
+
+private:
+ quint64 m_index;
+ std::vector<ExecutionNode*>* m_data= nullptr;
+};
+
+#endif // VARIABLENODE_H
diff --git a/src/libparser/operationcondition.cpp b/src/libparser/operationcondition.cpp
new file mode 100644
index 0000000..70ebab4
--- /dev/null
+++ b/src/libparser/operationcondition.cpp
@@ -0,0 +1,167 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "operationcondition.h"
+
+OperationCondition::OperationCondition()
+ : m_operator(Dice::ConditionOperator::Modulo), m_boolean(nullptr), m_value(nullptr)
+{
+}
+OperationCondition::~OperationCondition()
+{
+ if(m_value != nullptr)
+ {
+ delete m_value;
+ m_value= nullptr;
+ }
+}
+BooleanCondition* OperationCondition::getBoolean() const
+{
+ return m_boolean;
+}
+
+void OperationCondition::setBoolean(BooleanCondition* boolean)
+{
+ m_boolean= boolean;
+}
+
+qint64 OperationCondition::hasValid(Die* b, bool recursive, bool unhighlight) const
+{
+ if(nullptr == m_boolean)
+ {
+ return 0;
+ }
+ QList<qint64> listValues;
+ if(recursive)
+ {
+ listValues= b->getListValue();
+ }
+ else
+ {
+ listValues.append(b->getLastRolledValue());
+ }
+
+ qint64 sum= 0;
+ for(qint64& value : listValues)
+ {
+ switch(m_operator)
+ {
+ case Dice::ConditionOperator::Modulo:
+ {
+ Die die;
+ die.setMaxValue(b->getMaxValue());
+ auto valueScalar= valueToScalar();
+ if(valueScalar == 0)
+ valueScalar= 1;
+ die.insertRollValue(value % valueScalar);
+ sum+= m_boolean->hasValid(&die, recursive, false) ? 1 : 0;
+ }
+ break;
+ }
+ }
+ if((unhighlight) && (sum == 0))
+ {
+ b->setHighlighted(false);
+ }
+ else
+ {
+ b->setHighlighted(true);
+ }
+
+ return sum;
+}
+
+void OperationCondition::setOperator(Dice::ConditionOperator m)
+{
+ m_operator= m;
+}
+
+void OperationCondition::setValueNode(ExecutionNode* node)
+{
+ m_value= node;
+}
+
+QString OperationCondition::toString()
+{
+ QString str("");
+ switch(m_operator)
+ {
+ case Dice::ConditionOperator::Modulo:
+ str.append(QStringLiteral("\\%"));
+ break;
+ }
+ return QStringLiteral("[%1%2%3]").arg(str).arg(valueToScalar()).arg(m_boolean->toString());
+}
+Dice::CONDITION_STATE OperationCondition::isValidRangeSize(const std::pair<qint64, qint64>& range) const
+{
+ Dice::CONDITION_STATE valid= Dice::CONDITION_STATE::REACHABLE;
+
+ auto rangeIsClose= (range.first == range.second);
+
+ Die die;
+ die.insertRollValue(range.first);
+
+ if(nullptr == m_boolean)
+ return Dice::CONDITION_STATE::ERROR_STATE;
+
+ if(rangeIsClose && m_boolean->hasValid(&die, false, false))
+ valid= Dice::CONDITION_STATE::ALWAYSTRUE;
+ else if(rangeIsClose && !m_boolean->hasValid(&die, false, false))
+ valid= Dice::CONDITION_STATE::UNREACHABLE;
+
+ return valid;
+}
+
+Validator* OperationCondition::getCopy() const
+{
+ OperationCondition* val= new OperationCondition();
+ val->setOperator(m_operator);
+ val->setValueNode(m_value->getCopy());
+ BooleanCondition* boolean= dynamic_cast<BooleanCondition*>(m_boolean->getCopy());
+ val->setBoolean(boolean);
+ return val;
+}
+
+qint64 OperationCondition::valueToScalar() const
+{
+ if(m_value == nullptr)
+ return 0;
+
+ m_value->run(nullptr);
+ auto result= m_value->getResult();
+ return result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+}
+
+const std::set<qint64>& OperationCondition::getPossibleValues(const std::pair<qint64, qint64>& range)
+{
+ if(nullptr == m_boolean)
+ return m_values;
+
+ for(qint64 i= std::min(range.first, range.second); i <= std::max(range.first, range.second); ++i)
+ {
+ auto valueScalar= valueToScalar();
+ auto val= i % valueScalar;
+ Die die;
+ die.insertRollValue(val);
+ if(m_boolean->hasValid(&die, false, false))
+ m_values.insert(i);
+ }
+ return m_values;
+}
diff --git a/src/libparser/operationcondition.h b/src/libparser/operationcondition.h
new file mode 100644
index 0000000..719624f
--- /dev/null
+++ b/src/libparser/operationcondition.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * rolisteam is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef OPERATIONCONDITION_H
+#define OPERATIONCONDITION_H
+
+#include "booleancondition.h"
+#include "node/executionnode.h"
+#include "validator.h"
+#include <Qt>
+
+class OperationCondition : public Validator
+{
+public:
+ OperationCondition();
+ virtual ~OperationCondition() override;
+
+ virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override;
+
+ void setOperator(Dice::ConditionOperator m);
+ // void setValue(qint64);
+ void setValueNode(ExecutionNode* node);
+ QString toString() override;
+
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override;
+
+ BooleanCondition* getBoolean() const;
+ void setBoolean(BooleanCondition* boolean);
+
+ virtual Validator* getCopy() const override;
+
+ const std::set<qint64>& getPossibleValues(const std::pair<qint64, qint64>& range) override;
+
+private:
+ qint64 valueToScalar() const;
+
+private:
+ Dice::ConditionOperator m_operator{Dice::ConditionOperator::Modulo};
+ BooleanCondition* m_boolean= nullptr;
+ // qint64 m_value;
+ ExecutionNode* m_value= nullptr;
+};
+
+#endif // OPERATIONCONDITION_H
diff --git a/src/libparser/parsingtoolbox.cpp b/src/libparser/parsingtoolbox.cpp
new file mode 100644
index 0000000..dfde37f
--- /dev/null
+++ b/src/libparser/parsingtoolbox.cpp
@@ -0,0 +1,2641 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "diceparser/parsingtoolbox.h"
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QRegularExpression>
+#include <QString>
+#include <set>
+
+#include "node/allsamenode.h"
+#include "node/bind.h"
+#include "node/countexecutenode.h"
+#include "node/dicerollernode.h"
+#include "node/executionnode.h"
+#include "node/explodedicenode.h"
+#include "node/filternode.h"
+#include "node/groupnode.h"
+#include "node/helpnode.h"
+#include "node/ifnode.h"
+#include "node/jumpbackwardnode.h"
+#include "node/keepdiceexecnode.h"
+#include "node/listaliasnode.h"
+#include "node/listsetrollnode.h"
+#include "node/mergenode.h"
+#include "node/numbernode.h"
+#include "node/occurencecountnode.h"
+#include "node/paintnode.h"
+#include "node/parenthesesnode.h"
+#include "node/repeaternode.h"
+#include "node/replacevaluenode.h"
+#include "node/rerolldicenode.h"
+#include "node/scalaroperatornode.h"
+#include "node/sortresult.h"
+#include "node/splitnode.h"
+#include "node/startingnode.h"
+#include "node/stringnode.h"
+#include "node/switchcasenode.h"
+#include "node/uniquenode.h"
+#include "node/valueslistnode.h"
+#include "node/variablenode.h"
+#include "operationcondition.h"
+#include "range.h"
+#include "validatorlist.h"
+
+QHash<QString, QString> ParsingToolBox::m_variableHash;
+
+ParsingToolBox::ParsingToolBox()
+{
+ // m_logicOp = ;
+ m_logicOp.insert(">=", Dice::CompareOperator::GreaterOrEqual);
+ m_logicOp.insert("<=", Dice::CompareOperator::LesserOrEqual);
+ m_logicOp.insert("<", Dice::CompareOperator::LesserThan);
+ m_logicOp.insert("=", Dice::CompareOperator::Equal);
+ m_logicOp.insert(">", Dice::CompareOperator::GreaterThan);
+ m_logicOp.insert("!=", Dice::CompareOperator::Different);
+
+ // m_logicOperation = ;
+ m_logicOperation.insert("|", Dice::LogicOperation::OR);
+ m_logicOperation.insert("^", Dice::LogicOperation::EXCLUSIVE_OR);
+ m_logicOperation.insert("&", Dice::LogicOperation::AND);
+
+ // m_conditionOperation = ;
+ m_conditionOperation.insert("%", Dice::ConditionOperator::Modulo);
+
+ // m_arithmeticOperation = new QHash<QString,ScalarOperatorNode::ArithmeticOperator>();
+ m_arithmeticOperation.push_back({QStringLiteral("**"), Dice::ArithmeticOperator::POW});
+ m_arithmeticOperation.push_back({QStringLiteral("+"), Dice::ArithmeticOperator::PLUS});
+ m_arithmeticOperation.push_back({QStringLiteral("-"), Dice::ArithmeticOperator::MINUS});
+ m_arithmeticOperation.push_back({QStringLiteral("*"), Dice::ArithmeticOperator::MULTIPLICATION});
+ m_arithmeticOperation.push_back({QStringLiteral("x"), Dice::ArithmeticOperator::MULTIPLICATION});
+ m_arithmeticOperation.push_back({QStringLiteral("|"), Dice::ArithmeticOperator::INTEGER_DIVIDE});
+ m_arithmeticOperation.push_back({QStringLiteral("/"), Dice::ArithmeticOperator::DIVIDE});
+ m_arithmeticOperation.push_back({QStringLiteral("÷"), Dice::ArithmeticOperator::DIVIDE});
+
+ m_mapDiceOp.insert(QStringLiteral("D"), D);
+ m_mapDiceOp.insert(QStringLiteral("L"), L);
+
+ m_OptionOp.insert(QStringLiteral("k"), Keep);
+ m_OptionOp.insert(QStringLiteral("K"), KeepAndExplode);
+ m_OptionOp.insert(QStringLiteral("s"), Sort);
+ m_OptionOp.insert(QStringLiteral("c"), Count);
+ m_OptionOp.insert(QStringLiteral("r"), Reroll);
+ m_OptionOp.insert(QStringLiteral("e"), Explode);
+ m_OptionOp.insert(QStringLiteral("R"), RerollUntil);
+ m_OptionOp.insert(QStringLiteral("a"), RerollAndAdd);
+ m_OptionOp.insert(QStringLiteral("m"), Merge);
+ m_OptionOp.insert(QStringLiteral("i"), ifOperator);
+ m_OptionOp.insert(QStringLiteral("p"), Painter);
+ m_OptionOp.insert(QStringLiteral("f"), Filter);
+ m_OptionOp.insert(QStringLiteral("y"), Split);
+ m_OptionOp.insert(QStringLiteral("u"), Unique);
+ m_OptionOp.insert(QStringLiteral("t"), AllSameExplode);
+ m_OptionOp.insert(QStringLiteral("g"), Group);
+ m_OptionOp.insert(QStringLiteral("b"), Bind);
+ m_OptionOp.insert(QStringLiteral("o"), Occurences);
+ m_OptionOp.insert(QStringLiteral("S"), SwitchCaseOption);
+ m_OptionOp.insert(QStringLiteral("T"), TransformOption);
+
+ m_functionMap.insert({QStringLiteral("repeat"), REPEAT});
+
+ m_nodeActionMap.insert(QStringLiteral("@"), JumpBackward);
+
+ m_commandList.append(QStringLiteral("help"));
+ m_commandList.append(QStringLiteral("la"));
+}
+
+ParsingToolBox::ParsingToolBox(const ParsingToolBox&) {}
+ParsingToolBox::~ParsingToolBox() {}
+
+void ParsingToolBox::clearUp()
+{
+ m_errorMap.clear();
+ m_comment= QString("");
+}
+
+void ParsingToolBox::cleanUpAliases()
+{
+ m_aliasList.clear();
+}
+
+ExecutionNode* ParsingToolBox::addSort(ExecutionNode* e, bool b)
+{
+ SortResultNode* nodeSort= new SortResultNode();
+ nodeSort->setSortAscending(b);
+ if(nullptr != e)
+ e->setNextNode(nodeSort);
+ return nodeSort;
+}
+
+void ParsingToolBox::addError(Dice::ERROR_CODE code, const QString& msg)
+{
+ m_errorMap.insert(code, msg);
+}
+void ParsingToolBox::addWarning(Dice::ERROR_CODE code, const QString& msg)
+{
+ m_warningMap.insert(code, msg);
+}
+bool ParsingToolBox::readDiceLogicOperator(QString& str, Dice::ConditionOperator& op)
+{
+ QString longKey;
+ auto const& keys= m_conditionOperation.keys();
+ for(const QString& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_conditionOperation.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readArithmeticOperator(QString& str, Dice::ArithmeticOperator& op)
+{
+
+ auto it= std::find_if(m_arithmeticOperation.begin(), m_arithmeticOperation.end(),
+ [str](const std::pair<QString, Dice::ArithmeticOperator>& pair)
+ { return str.startsWith(pair.first); });
+ if(it == m_arithmeticOperation.end())
+ return false;
+
+ op= it->second;
+ str= str.remove(0, it->first.size());
+ return true;
+}
+
+bool ParsingToolBox::readLogicOperator(QString& str, Dice::CompareOperator& op)
+{
+ QString longKey;
+ auto const& keys= m_logicOp.keys();
+ for(const QString& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_logicOp.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+QString ParsingToolBox::getComment() const
+{
+ return m_comment;
+}
+
+void ParsingToolBox::setComment(const QString& comment)
+{
+ m_comment= comment;
+}
+const QMap<Dice::ERROR_CODE, QString>& ParsingToolBox::getErrorList() const
+{
+ return m_errorMap;
+}
+const QMap<Dice::ERROR_CODE, QString>& ParsingToolBox::getWarningList() const
+{
+ return m_warningMap;
+}
+bool ParsingToolBox::readOperand(QString& str, ExecutionNode*& node)
+{
+ qint64 intValue= 1;
+ QString resultStr;
+ if(readDynamicVariable(str, intValue))
+ {
+ VariableNode* variableNode= new VariableNode();
+ variableNode->setIndex(static_cast<quint64>(intValue - 1));
+ variableNode->setData(&m_startNodes);
+ node= variableNode;
+ return true;
+ }
+ else if(readNumber(str, intValue))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(intValue);
+ node= numberNode;
+ return true;
+ }
+ else if(readString(str, resultStr))
+ {
+ StringNode* strNode= new StringNode();
+ strNode->setString(resultStr);
+ node= strNode;
+ return true;
+ }
+ return false;
+}
+
+Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare)
+{
+ Validator* returnVal= nullptr;
+ auto opCompare= readConditionType(str);
+ Dice::CompareOperator myLogicOp{Dice::CompareOperator::Equal};
+ readLogicOperator(str, myLogicOp);
+
+ Dice::ConditionOperator condiOp{Dice::ConditionOperator::Modulo};
+ bool hasDiceLogicOperator= readDiceLogicOperator(str, condiOp);
+ ExecutionNode* operandNode= nullptr;
+ if(hasDiceLogicOperator)
+ {
+ if(readOperand(str, operandNode))
+ {
+ OperationCondition* condition= new OperationCondition();
+ condition->setConditionType(opCompare);
+ condition->setValueNode(operandNode);
+ Validator* valid= readValidator(str, hasSquare);
+ BooleanCondition* boolC= dynamic_cast<BooleanCondition*>(valid);
+ if(nullptr != boolC)
+ {
+ condition->setBoolean(boolC);
+ returnVal= condition;
+ }
+ else
+ {
+ delete condition;
+ }
+ }
+ }
+ else if(readOperand(str, operandNode))
+ {
+ bool isRange= false;
+ if(str.startsWith("..") && hasSquare)
+ {
+ str= str.remove(0, 2);
+ qint64 end= 0;
+ if(readNumber(str, end))
+ {
+ str= str.remove(0, 1);
+ qint64 start= operandNode->getScalarResult();
+ Range* range= new Range();
+ range->setConditionType(opCompare);
+ range->setValue(start, end);
+ returnVal= range;
+ isRange= true;
+ }
+ }
+
+ if(!isRange)
+ {
+ BooleanCondition* condition= new BooleanCondition();
+ condition->setConditionType(opCompare);
+ condition->setValueNode(operandNode);
+ condition->setOperator(myLogicOp);
+ returnVal= condition;
+ }
+ }
+ return returnVal;
+}
+
+Dice::ConditionType ParsingToolBox::readConditionType(QString& str)
+{
+ Dice::ConditionType type= Dice::OnEach;
+ if(str.startsWith('.'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OneOfThem;
+ }
+ else if(str.startsWith('?'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OnEachValue;
+ }
+ else if(str.startsWith('*'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::AllOfThem;
+ }
+ else if(str.startsWith(':'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OnScalar;
+ }
+ return type;
+}
+bool ParsingToolBox::hasError() const
+{
+ return !m_errorMap.isEmpty();
+}
+ValidatorList* ParsingToolBox::readValidatorList(QString& str)
+{
+ bool expectSquareBrasket= false;
+ if((str.startsWith("[")))
+ {
+ str= str.remove(0, 1);
+ expectSquareBrasket= true;
+ }
+ Validator* tmp= readValidator(str, expectSquareBrasket);
+ Dice::LogicOperation opLogic;
+
+ QVector<Dice::LogicOperation> operators;
+ QList<Validator*> validatorList;
+
+ while(nullptr != tmp)
+ {
+ bool hasOperator= readLogicOperation(str, opLogic);
+ if(hasOperator)
+ {
+ operators.append(opLogic);
+ validatorList.append(tmp);
+ tmp= readValidator(str, expectSquareBrasket);
+ }
+ else
+ {
+ if((expectSquareBrasket) && (str.startsWith("]")))
+ {
+ str= str.remove(0, 1);
+ // isOk=true;
+ }
+ validatorList.append(tmp);
+ tmp= nullptr;
+ }
+ }
+ if(!validatorList.isEmpty())
+ {
+ ValidatorList* validator= new ValidatorList();
+ validator->setOperationList(operators);
+ validator->setValidators(validatorList);
+ return validator;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+bool ParsingToolBox::readLogicOperation(QString& str, Dice::LogicOperation& op)
+{
+ QString longKey;
+ auto const& keys= m_logicOperation.keys();
+ for(auto& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_logicOperation.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readNumber(QString& str, qint64& myNumber)
+{
+ if(str.isEmpty())
+ return false;
+
+ QString number;
+ int i= 0;
+ while(i < str.length() && ((str[i].isNumber()) || ((i == 0) && (str[i] == '-'))))
+ {
+ number+= str[i];
+ ++i;
+ }
+
+ if(number.isEmpty())
+ {
+ QString reason;
+ return readVariable(str, myNumber, reason);
+ }
+
+ bool ok;
+ myNumber= number.toLongLong(&ok);
+ if(ok)
+ {
+ str= str.remove(0, number.size());
+ return true;
+ }
+
+ return false;
+}
+bool ParsingToolBox::readDynamicVariable(QString& str, qint64& index)
+{
+ if(str.isEmpty())
+ return false;
+ if(str.startsWith('$'))
+ {
+ QString number;
+ int i= 1;
+ while(i < str.length() && (str[i].isNumber()))
+ {
+ number+= str[i];
+ ++i;
+ }
+
+ bool ok;
+ index= number.toLongLong(&ok);
+ if(ok)
+ {
+ str= str.remove(0, number.size() + 1);
+ return true;
+ }
+ }
+ return false;
+}
+
+ExecutionNode* ParsingToolBox::getLeafNode(ExecutionNode* start)
+{
+ if(nullptr == start)
+ return nullptr;
+
+ ExecutionNode* next= start;
+ while(nullptr != next->getNextNode())
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+
+const std::vector<ExecutionNode*>& ParsingToolBox::getStartNodes()
+{
+ return m_startNodes;
+}
+
+QStringList ParsingToolBox::allFirstResultAsString(bool& hasAlias) const
+{
+ // QStringList allResult;
+ QStringList stringListResult;
+ for(auto node : m_startNodes)
+ {
+ QVariant var;
+ auto stringPair= hasResultOfType(Dice::RESULT_TYPE::STRING, node);
+ auto scalarPair= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node);
+ if(stringPair.first)
+ {
+ stringListResult << stringPair.second.toString();
+ hasAlias= true;
+ }
+ else if(scalarPair.first)
+ {
+ stringListResult << number(scalarPair.second.toReal());
+ hasAlias= true;
+ }
+ }
+ return stringListResult;
+}
+std::pair<bool, QVariant> ParsingToolBox::hasResultOfType(Dice::RESULT_TYPE type, ExecutionNode* node,
+ bool notthelast) const
+{
+ bool hasValidResult= false;
+ QVariant var;
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ while((result != nullptr) && (!hasValidResult))
+ {
+ bool lastResult= false;
+ if(notthelast)
+ lastResult= (nullptr == result->getPrevious());
+
+ if(result->hasResultOfType(type) && !lastResult)
+ {
+ hasValidResult= true;
+ var= result->getResult(type);
+ }
+ result= result->getPrevious();
+ }
+ return {hasValidResult, var};
+}
+
+QList<qreal> ParsingToolBox::scalarResultsFromEachInstruction() const
+{
+ QList<qreal> resultValues;
+ std::set<QString> alreadyVisitedNode;
+ for(auto node : m_startNodes)
+ {
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ bool scalarDone= false;
+ while((result != nullptr) && (!scalarDone))
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::SCALAR))
+ {
+ if(alreadyVisitedNode.find(result->getId()) == alreadyVisitedNode.end())
+ {
+ resultValues << result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ alreadyVisitedNode.insert(result->getId());
+ }
+ scalarDone= true;
+ }
+ result= result->getPrevious();
+ }
+ }
+ return resultValues;
+}
+
+QList<qreal> ParsingToolBox::sumOfDiceResult() const
+{
+ QList<qreal> resultValues;
+ for(auto node : m_startNodes)
+ {
+ qreal resultValue= 0;
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ bool found= false;
+ while((nullptr != result) && (!found))
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* myDiceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != myDiceResult)
+ {
+ for(auto& die : myDiceResult->getResultList())
+ {
+ resultValue+= die->getValue();
+ }
+ found= true;
+ }
+ }
+ result= result->getPrevious();
+ }
+ resultValues << resultValue;
+ }
+ return resultValues;
+}
+
+std::pair<QString, QString> ParsingToolBox::finalScalarResult() const
+{
+ QString scalarText;
+ QString lastScalarText;
+ auto listDie= diceResultFromEachInstruction();
+ if(hasIntegerResultNotInFirst())
+ {
+ QStringList strLst;
+ auto listScalar= scalarResultsFromEachInstruction();
+ for(auto val : listScalar)
+ {
+ strLst << number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+ lastScalarText= strLst.last();
+ }
+ else if(!listDie.isEmpty())
+ {
+ auto values= sumOfDiceResult();
+ QStringList strLst;
+ for(auto val : values)
+ {
+ strLst << number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+ }
+ return {scalarText, lastScalarText};
+}
+
+bool ParsingToolBox::hasIntegerResultNotInFirst() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node, true).first;
+ }
+ return result;
+}
+
+bool ParsingToolBox::hasDiceResult() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::DICE_LIST, node).first;
+ }
+ return result;
+}
+bool ParsingToolBox::hasStringResult() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::STRING, node).first;
+ }
+ return result;
+}
+
+QList<ExportedDiceResult> ParsingToolBox::diceResultFromEachInstruction() const
+{
+ QList<ExportedDiceResult> resultList;
+ for(auto start : m_startNodes)
+ {
+ resultList.append(ParsingToolBox::finalDiceResultFromInstruction(start));
+ }
+ return resultList;
+}
+
+QStringList listOfDiceResult(const QList<ExportedDiceResult>& list, bool removeDouble= false)
+{
+ QStringList listOfDiceResult;
+ std::set<QString> alreadyAdded;
+ for(auto map : list)
+ {
+ for(auto key : map.keys())
+ {
+ auto listOfList= map.value(key);
+ for(auto dice : listOfList)
+ {
+ QString stringVal;
+ for(auto val : dice)
+ {
+ if(removeDouble && (alreadyAdded.end() != alreadyAdded.find(val.uuid())))
+ continue;
+
+ alreadyAdded.insert(val.uuid());
+
+ qint64 total= 0;
+ QStringList dicelist;
+ for(auto score : val.result())
+ {
+ total+= score;
+ dicelist << QString::number(score);
+ }
+ if(val.result().size() > 1)
+ {
+ stringVal= QString("%1 [%2]").arg(total).arg(dicelist.join(','));
+ listOfDiceResult << stringVal;
+ }
+ else
+ {
+ listOfDiceResult << QString::number(total);
+ }
+ }
+ }
+ }
+ }
+ return listOfDiceResult;
+}
+
+QString ParsingToolBox::finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize,
+ bool removeUnhighlighted) const
+{
+ bool ok;
+ QStringList allStringlist= allFirstResultAsString(ok);
+ auto listFull= diceResultFromEachInstruction();
+
+ QStringList resultWithPlaceHolder;
+ std::for_each(allStringlist.begin(), allStringlist.end(),
+ [&resultWithPlaceHolder](const QString& sub)
+ {
+ QRegularExpression ex("%[1-3]?|\\$[1-9]+|@[1-9]+");
+ if(sub.contains(ex))
+ resultWithPlaceHolder.append(sub);
+ });
+ auto stringResult= resultWithPlaceHolder.isEmpty() ? allStringlist.join(",") : resultWithPlaceHolder.join(",");
+
+ auto pairScalar= finalScalarResult();
+
+ stringResult.replace("%1", pairScalar.first);
+ stringResult.replace("%2", listOfDiceResult(diceResultFromEachInstruction(), true).join(",").trimmed());
+ stringResult.replace("%3", pairScalar.second);
+ stringResult.replace("\\n", "\n");
+
+ QMap<Dice::ERROR_CODE, QString> errorMap;
+ stringResult= ParsingToolBox::replaceVariableToValue(stringResult, allStringlist, errorMap);
+ stringResult= ParsingToolBox::replacePlaceHolderToValue(stringResult, listFull, removeUnhighlighted, colorize);
+
+ return stringResult;
+}
+
+bool ParsingToolBox::readString(QString& str, QString& strResult)
+{
+ if(str.isEmpty())
+ return false;
+
+ if(str.startsWith('"'))
+ {
+ str= str.remove(0, 1);
+
+ int i= 0;
+ int j= 0;
+ bool previousEscape= false;
+ QString result;
+ /*&&
+ (((!previousEscape) && !(str[i]=='"')) || (previousEscape) && !(str[i]=='"'))
+ || (str[i]=='\\'))*/
+ while(i < str.length() && (!(!previousEscape && (str[i] == '"')) || (previousEscape && str[i] != '"')))
+ {
+ if(str[i] == '\\')
+ {
+ previousEscape= true;
+ }
+ else
+ {
+ if(previousEscape && str[i] != '\"')
+ {
+ result+= '\\';
+ ++j;
+ }
+ result+= str[i];
+ previousEscape= false;
+ }
+ ++i;
+ }
+
+ if(!result.isEmpty())
+ {
+ str= str.remove(0, i);
+ strResult= result;
+ if(str.startsWith('"'))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readVariable(QString& str, qint64& myNumber, QString& reasonFail)
+{
+ if(str.isEmpty())
+ return false;
+
+ if(str.startsWith("${"))
+ {
+ str= str.remove(0, 2);
+ }
+ QString key;
+ int post= str.indexOf('}');
+ key= str.left(post);
+
+ if(!m_variableHash.isEmpty())
+ {
+ if(m_variableHash.contains(key))
+ {
+ QString value= m_variableHash.value(key);
+ bool ok;
+ int valueInt= value.toInt(&ok);
+ if(ok)
+ {
+ myNumber= valueInt;
+ str= str.remove(0, post + 1);
+ return true;
+ }
+ else
+ {
+ reasonFail= QStringLiteral("Variable value is %1, not a number").arg(value);
+ }
+ }
+ else
+ {
+ reasonFail= QStringLiteral("Variable not found");
+ }
+ }
+ else
+ {
+ reasonFail= QStringLiteral("No Variables are defined");
+ }
+
+ return false;
+}
+bool ParsingToolBox::readComma(QString& str)
+{
+ if(str.startsWith(","))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+bool ParsingToolBox::readOpenParentheses(QString& str)
+{
+ if(str.startsWith("("))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool ParsingToolBox::readCloseParentheses(QString& str)
+{
+ if(str.startsWith(")"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+
+int ParsingToolBox::findClosingCharacterIndexOf(QChar open, QChar closing, const QString& str, int offset)
+{
+ int counter= offset;
+ int i= 0;
+ for(auto const& letter : str)
+ {
+ if(letter == open)
+ ++counter;
+ else if(letter == closing)
+ --counter;
+
+ if(counter == 0)
+ return i;
+
+ ++i;
+ }
+ return -1;
+}
+
+bool ParsingToolBox::readList(QString& str, QStringList& list, QList<Range>& ranges)
+{
+ if(str.startsWith("["))
+ {
+ str= str.remove(0, 1);
+ int pos= findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]");
+ if(-1 != pos)
+ {
+ QString liststr= str.left(pos);
+ list= liststr.split(",");
+ str= str.remove(0, pos + 1);
+ readProbability(list, ranges);
+ return true;
+ }
+ }
+ return false;
+}
+bool ParsingToolBox::readAscending(QString& str)
+{
+ if(str.isEmpty())
+ {
+ return false;
+ }
+ else if(str.at(0) == 'l')
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readStopAtFirst(QString& str)
+{
+ if(str.isEmpty())
+ return false;
+ else if(str.at(0) == '^')
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+
+Dice::CONDITION_STATE ParsingToolBox::isValidValidator(ExecutionNode* previous, ValidatorList* val)
+{
+ DiceRollerNode* node= getDiceRollerNode(previous);
+ if(nullptr == node)
+ return Dice::CONDITION_STATE::ERROR_STATE;
+
+ return val->isValidRangeSize(node->getRange());
+}
+DiceRollerNode* ParsingToolBox::getDiceRollerNode(ExecutionNode* previous)
+{
+ while(nullptr != previous)
+ {
+ DiceRollerNode* node= dynamic_cast<DiceRollerNode*>(previous);
+ if(nullptr != node)
+ {
+ return node;
+ }
+ previous= previous->getPreviousNode();
+ }
+ return nullptr;
+}
+bool ParsingToolBox::readDiceRange(QString& str, qint64& start, qint64& end)
+{
+ bool expectSquareBrasket= false;
+
+ if((str.startsWith("[")))
+ {
+ str= str.remove(0, 1);
+ expectSquareBrasket= true;
+ }
+ if(readNumber(str, start))
+ {
+ if(str.startsWith(".."))
+ {
+ str= str.remove(0, 2);
+ if(readNumber(str, end))
+ {
+ if(expectSquareBrasket)
+ {
+ if(str.startsWith("]"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ }
+ else if(expectSquareBrasket)
+ {
+ if(str.startsWith("]"))
+ {
+ str= str.remove(0, 1);
+ end= start;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+ParsingToolBox::LIST_OPERATOR ParsingToolBox::readListOperator(QString& str)
+{
+ QHash<QChar, ParsingToolBox::LIST_OPERATOR> hash;
+ hash.insert('u', UNIQUE);
+ hash.insert('n', NOCOMMA);
+ bool findOne= false;
+ ParsingToolBox::LIST_OPERATOR op= NONE;
+ int i= 0;
+ do
+ {
+ auto keys= hash.keys();
+ findOne= false;
+ for(auto const& key : qAsConst(keys))
+ {
+ if(str.startsWith(key))
+ {
+ str= str.remove(0, 1);
+ op= hash[key];
+ findOne= true;
+ ++i;
+ }
+ }
+ } while(findOne);
+
+ return i > 1 ? UniqueAndNoComma : op;
+}
+
+bool ParsingToolBox::readPainterParameter(PainterNode* painter, QString& str)
+{
+ if(!str.startsWith('['))
+ return false;
+
+ str= str.remove(0, 1);
+ int pos= str.indexOf(']');
+
+ if(pos == -1)
+ return false;
+
+ QString data= str.left(pos);
+ str= str.remove(0, pos + 1);
+ QStringList duos= data.split(',');
+ bool result= false;
+ for(QString& duoStr : duos)
+ {
+ QStringList keyValu= duoStr.split(':');
+ if(keyValu.size() == 2)
+ {
+ painter->insertColorItem(keyValu[1], keyValu[0].toInt());
+ result= true;
+ }
+ }
+
+ return result;
+}
+
+QHash<QString, QString> ParsingToolBox::getVariableHash()
+{
+ return m_variableHash;
+}
+
+void ParsingToolBox::setVariableHash(const QHash<QString, QString>& variableHash)
+{
+ m_variableHash= variableHash;
+}
+
+void ParsingToolBox::setStartNodes(std::vector<ExecutionNode*> nodes)
+{
+ m_startNodes= nodes;
+}
+
+void ParsingToolBox::readProbability(QStringList& str, QList<Range>& ranges)
+{
+ quint64 totalDistance= 0;
+ quint64 undefDistance= 0;
+ int undefCount= 0;
+ int maxValue= 0;
+ int i= 0;
+ int j= 0;
+ bool hasPercentage= false;
+ for(QString line : str)
+ {
+ int pos= line.indexOf('[');
+ if(-1 != pos)
+ {
+ QString rangeStr= line.right(line.length() - pos);
+ line= line.left(pos);
+ str[j]= line;
+ qint64 start= 0;
+ qint64 end= 0;
+ if(readDiceRange(rangeStr, start, end))
+ {
+ Range range;
+ range.setValue(start, end);
+ ranges.append(range);
+ totalDistance+= static_cast<quint64>(end - start + 1);
+ ++i;
+ }
+ else // percentage
+ {
+ hasPercentage= true;
+ Range range;
+ range.setStart(start);
+ ranges.append(range);
+ ++undefCount;
+ undefDistance+= static_cast<quint64>(start);
+ }
+ if((end > maxValue) || (i == 1))
+ {
+ maxValue= static_cast<int>(end);
+ }
+ }
+ else
+ {
+ Range range;
+ range.setEmptyRange(true);
+ ranges.append(range);
+ }
+ ++j;
+ }
+
+ if((hasPercentage) && (undefDistance != 0))
+ {
+ qreal ratio= 100.0 / static_cast<qreal>(undefDistance);
+ qint64 realStart= 0;
+ for(int i= 0; i < ranges.size(); ++i)
+ {
+ Range tmp= ranges.at(i);
+ if(!tmp.isFullyDefined())
+ {
+ int dist= static_cast<int>(tmp.getStart());
+ tmp.setStart(realStart + 1);
+ double truc= dist * ratio;
+
+ tmp.setEnd(static_cast<int>(realStart + truc));
+ realStart= tmp.getEnd();
+ ranges[i]= tmp;
+ }
+ }
+ }
+ else
+ {
+ int limitUp= 1;
+ for(int i= 0; i < ranges.size(); ++i)
+ {
+ Range range= ranges.at(i);
+ if(range.isEmptyRange())
+ {
+ range.setStart(limitUp);
+ range.setEnd(limitUp);
+ range.setEmptyRange(false);
+ }
+ else
+ {
+ qint64 sizeRange= range.getEnd() - range.getStart();
+ range.setStart(limitUp);
+ limitUp+= sizeRange;
+ range.setEnd(limitUp);
+ }
+ ++limitUp;
+ ranges[i]= range;
+ }
+ }
+}
+bool ParsingToolBox::readComment(QString& str, QString& result, QString& comment)
+{
+ QString left= str;
+ str= str.trimmed();
+ if(str.startsWith("#"))
+ {
+ comment= left;
+ str= str.remove(0, 1);
+ result= str.trimmed();
+ str= "";
+ return true;
+ }
+ return false;
+}
+
+QString ParsingToolBox::replaceVariableToValue(const QString& source, QStringList values,
+ QMap<Dice::ERROR_CODE, QString>& errorMap)
+{
+ QString result= source;
+
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readVariableFromString(source, start);
+ if(ref.resultIndex() > values.size())
+ {
+ auto error= QString("No valid value at index: $%1").arg(ref.resultIndex());
+ errorMap.insert(Dice::ERROR_CODE::INVALID_INDEX, error);
+ return error;
+ }
+
+ valid= ref.isValid();
+ if(!valid)
+ continue;
+
+ result.remove(ref.position(), ref.length());
+ auto val= values[ref.resultIndex() - 1];
+
+ if(ref.subIndex() >= 0)
+ {
+ auto valSplit= val.split(",");
+ if(ref.subIndex() < valSplit.size())
+ val= valSplit[ref.subIndex()];
+ }
+
+ if(ref.digitNumber() != 0)
+ {
+ auto realVal= QString("%1").arg(val, ref.digitNumber(), QChar('0'));
+ result.insert(ref.position(), realVal);
+ }
+ else
+ {
+ result.insert(ref.position(), val);
+ }
+ } while(valid);
+
+ return result;
+}
+
+QString ParsingToolBox::replacePlaceHolderFromJson(const QString& source, const QJsonObject& obj)
+{
+ QStringList resultList;
+ auto instructions= obj["instructions"].toArray();
+ std::vector<std::vector<std::pair<int, QList<QStringList>>>> instructionResult;
+ for(auto inst : qAsConst(instructions))
+ {
+ std::vector<std::pair<int, QList<QStringList>>> map;
+ auto obj= inst.toObject();
+ auto vals= obj["diceval"].toArray();
+ int lastFace= -1;
+ for(auto const& valRef : qAsConst(vals))
+ {
+ auto diceObj= valRef.toObject();
+ auto face= diceObj["face"].toInt();
+ auto it= std::find_if(std::begin(map), std::end(map),
+ [face](const std::pair<int, QList<QStringList>>& val) { return val.first == face; });
+
+ auto realVal= diceObj["string"].toString();
+ if(lastFace == -1 || lastFace != face)
+ {
+ QList<QStringList> listOfList;
+ listOfList << (QStringList() << realVal);
+ map.push_back({face, listOfList});
+ }
+ else if(lastFace == face)
+ {
+ auto& valList= it->second.last();
+ valList.append(realVal);
+ }
+ lastFace= face;
+ }
+ instructionResult.push_back(map);
+ }
+ std::transform(std::begin(instructionResult), std::end(instructionResult), std::back_inserter(resultList),
+ [](const std::vector<std::pair<int, QList<QStringList>>>& map)
+ {
+ QStringList valuesStr;
+ auto multiKey= (map.size() > 1);
+ for(auto item : map)
+ {
+ auto face= item.first;
+ auto valueList= item.second;
+ QStringList strs;
+ for(auto list : valueList)
+ {
+ strs << list.join(",");
+ }
+ if(!multiKey)
+ valuesStr << strs.join(",");
+ else
+ valuesStr << QString("d%1:(%2)").arg(face).arg(strs.join(","));
+ }
+ return valuesStr.join(" - ");
+ });
+
+ QString result= source;
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readPlaceHolderFromString(source, start);
+ if(ref.isValid())
+ {
+ result.remove(ref.position(), ref.length());
+ auto val= resultList[ref.resultIndex() - 1];
+ result.insert(ref.position(), val);
+ }
+ else
+ {
+ valid= false;
+ }
+ } while(valid);
+
+ return result;
+}
+
+QString ParsingToolBox::replacePlaceHolderToValue(const QString& source, const QList<ExportedDiceResult>& list,
+ bool removeUnhighlighted,
+ std::function<QString(const QString&, const QString&, bool)> colorize)
+{
+ QStringList resultList;
+ std::transform(
+ std::begin(list), std::end(list), std::back_inserter(resultList),
+ [removeUnhighlighted, colorize](const ExportedDiceResult& dice)
+ {
+ QStringList valuesStr;
+ if(dice.size() == 1)
+ {
+ auto values= dice.values();
+ std::transform(
+ std::begin(values), std::end(values), std::back_inserter(valuesStr),
+ [removeUnhighlighted, colorize](const QList<ListDiceResult>& dice)
+ {
+ QStringList textList;
+ std::transform(
+ std::begin(dice), std::end(dice), std::back_inserter(textList),
+ [removeUnhighlighted, colorize](const ListDiceResult& dice)
+ {
+ QStringList list;
+ ListDiceResult values= dice;
+ if(removeUnhighlighted)
+ {
+ values.clear();
+ std::copy_if(std::begin(dice), std::end(dice), std::back_inserter(values),
+ [](const HighLightDice& hl) { return hl.isHighlighted(); });
+ }
+
+ std::transform(std::begin(values), std::end(values), std::back_inserter(list),
+ [colorize](const HighLightDice& hl)
+ { return colorize(hl.getResultString(), {}, hl.isHighlighted()); });
+ return list.join(",");
+ });
+ textList.removeAll(QString());
+ return textList.join(",");
+ });
+ }
+ else if(dice.size() > 1)
+ {
+ for(auto key : dice.keys())
+ {
+ auto list= dice.value(key);
+ for(auto values : list)
+ {
+ QStringList textVals;
+ std::transform(std::begin(values), std::end(values), std::back_inserter(textVals),
+ [](const HighLightDice& dice) { return dice.getResultString(); });
+ valuesStr.append(QString("d%1 [%2]").arg(key).arg(textVals.join(",")));
+ }
+ }
+ }
+ return valuesStr.join(",");
+ });
+
+ QString result= source;
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readPlaceHolderFromString(source, start);
+ if(ref.isValid())
+ {
+ result.remove(ref.position(), ref.length());
+ auto val= resultList[ref.resultIndex() - 1];
+ result.insert(ref.position(), val);
+ }
+ else
+ {
+ valid= false;
+ }
+ } while(valid);
+
+ return result;
+}
+void ParsingToolBox::readSubtitutionParameters(SubtituteInfo& info, QString& rest)
+{
+ auto sizeS= rest.size();
+ if(rest.startsWith("{"))
+ {
+ rest= rest.remove(0, 1);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ if(rest.startsWith("}"))
+ {
+ rest= rest.remove(0, 1);
+ info.setDigitNumber(static_cast<int>(number));
+ }
+ }
+ }
+ if(rest.startsWith("["))
+ {
+ rest= rest.remove(0, 1);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ if(rest.startsWith("]"))
+ {
+ rest= rest.remove(0, 1);
+ info.setSubIndex(static_cast<int>(number));
+ }
+ }
+ }
+ info.setLength(info.length() + sizeS - rest.size());
+}
+
+bool ParsingToolBox::readReaperArguments(RepeaterNode* node, QString& source)
+{
+ if(!readOpenParentheses(source))
+ return false;
+
+ auto instructions= readInstructionList(source, false);
+ if(instructions.empty())
+ return false;
+
+ readComma(source);
+ ExecutionNode* tmp;
+ if(readOperand(source, tmp))
+ {
+ if(source.startsWith("+"))
+ {
+ node->setSumAll(true);
+ source= source.remove(0, 1);
+ }
+ if(readCloseParentheses(source))
+ {
+ node->setCommand(instructions);
+ node->setTimeNode(tmp);
+ return true;
+ }
+ }
+
+ return false;
+}
+bool ParsingToolBox::readExpression(QString& str, ExecutionNode*& node)
+{
+ ExecutionNode* operandNode= nullptr;
+ if(readOpenParentheses(str))
+ {
+ ExecutionNode* internalNode= nullptr;
+ if(readExpression(str, internalNode))
+ {
+ ParenthesesNode* parentheseNode= new ParenthesesNode();
+ parentheseNode->setInternelNode(internalNode);
+ node= parentheseNode;
+ if(readCloseParentheses(str))
+ {
+ ExecutionNode* diceNode= nullptr;
+ ExecutionNode* operatorNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ parentheseNode->setNextNode(diceNode);
+ }
+ else if(readExpression(str, operatorNode))
+ {
+ parentheseNode->setNextNode(operatorNode);
+ }
+ return true;
+ }
+ else
+ {
+ m_warningMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Expected closing parenthesis - can't validate the inside."));
+ }
+ }
+ }
+ else if(readFunction(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOptionFromNull(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOperatorFromNull(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOperand(str, operandNode))
+ {
+ ExecutionNode* diceNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ operandNode->setNextNode(diceNode);
+ }
+ node= operandNode;
+
+ operandNode= ParsingToolBox::getLeafNode(operandNode);
+ // ExecutionNode* operatorNode=nullptr;
+ while(readOperator(str, operandNode))
+ {
+ // operandNode->setNextNode(operatorNode);
+ operandNode= ParsingToolBox::getLeafNode(operandNode);
+ }
+ return true;
+ }
+ else if(readCommand(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readNode(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readValuesList(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else
+ {
+ ExecutionNode* diceNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(1);
+ numberNode->setNextNode(diceNode);
+ node= numberNode;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool ParsingToolBox::readValuesList(QString& str, ExecutionNode*& node)
+{
+ if(!str.startsWith("["))
+ return false;
+
+ str= str.remove(0, 1);
+ int pos= ParsingToolBox::findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]");
+ if(-1 == pos)
+ return false;
+
+ QString liststr= str.left(pos);
+ auto list= liststr.split(",");
+ str= str.remove(0, pos + 1);
+ auto values= new ValuesListNode();
+ for(auto var : qAsConst(list))
+ {
+ qint64 number= 1;
+ var= var.trimmed();
+ if(ParsingToolBox::readDynamicVariable(var, number))
+ {
+ VariableNode* variableNode= new VariableNode();
+ variableNode->setIndex(static_cast<quint64>(number - 1));
+ variableNode->setData(&m_startNodes);
+ values->insertValue(variableNode);
+ }
+ else if(ParsingToolBox::readNumber(var, number))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(number);
+ values->insertValue(numberNode);
+ }
+ }
+ node= values;
+ return true;
+}
+bool ParsingToolBox::readOptionFromNull(QString& str, ExecutionNode*& node)
+{
+ StartingNode nodePrevious;
+ if(readOption(str, &nodePrevious))
+ {
+ auto nodeNext= nodePrevious.getNextNode();
+ nodePrevious.setNextNode(nullptr);
+ node= nodeNext;
+ return true;
+ }
+ return false;
+}
+
+void ParsingToolBox::setHelpPath(const QString& path)
+{
+ m_helpPath= path;
+}
+
+bool ParsingToolBox::readOperatorFromNull(QString& str, ExecutionNode*& node)
+{
+ StartingNode nodePrevious;
+ if(readOperator(str, &nodePrevious))
+ {
+ auto nodeNext= nodePrevious.getNextNode();
+ nodePrevious.setNextNode(nullptr);
+ node= nodeNext;
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readOption(QString& str, ExecutionNode* previous) //,
+{
+ if(str.isEmpty())
+ {
+ return false;
+ }
+
+ bool found= false;
+ auto keys= m_OptionOp.keys();
+ for(int i= 0; ((i < keys.size()) && (!found)); ++i)
+ {
+ QString key= keys.at(i);
+
+ if(str.startsWith(key))
+ {
+ str= str.remove(0, key.size());
+ auto operatorName= m_OptionOp.value(key);
+ switch(operatorName)
+ {
+ case Keep:
+ {
+ ExecutionNode* value= nullptr;
+ bool ascending= readAscending(str);
+
+ if(readOperand(str, value))
+ {
+ auto node= addSort(previous, ascending);
+ KeepDiceExecNode* nodeK= new KeepDiceExecNode();
+ nodeK->setDiceKeepNumber(value);
+ node->setNextNode(nodeK);
+ found= true;
+ }
+ }
+ break;
+ case KeepAndExplode:
+ {
+ bool ascending= readAscending(str);
+ ExecutionNode* value= nullptr;
+ if(readOperand(str, value))
+ {
+ DiceRollerNode* nodeTmp= dynamic_cast<DiceRollerNode*>(previous);
+ if(nullptr != nodeTmp)
+ {
+ previous= addExplodeDiceNode(static_cast<qint64>(nodeTmp->getFaces()), previous);
+ }
+
+ auto node= addSort(previous, ascending);
+
+ KeepDiceExecNode* nodeK= new KeepDiceExecNode();
+ nodeK->setDiceKeepNumber(value);
+
+ node->setNextNode(nodeK);
+ node= nodeK;
+ found= true;
+ }
+ }
+ break;
+ case Filter:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ auto validity= isValidValidator(previous, validatorList);
+
+ FilterNode* filterNode= new FilterNode();
+ filterNode->setValidatorList(validatorList);
+
+ previous->setNextNode(filterNode);
+ found= true;
+ }
+ }
+ break;
+ case Sort:
+ {
+ bool ascending= readAscending(str);
+ addSort(previous, ascending);
+ /*if(!hasDice)
+ {
+ m_errorMap.insert(ExecutionNode::BAD_SYNTAXE,QObject::tr("Sort Operator does not support default
+ dice. You should add dice command before the s"));
+ }*/
+ found= true;
+ }
+ break;
+ case Count:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ auto validity= isValidValidator(previous, validatorList);
+
+ CountExecuteNode* countNode= new CountExecuteNode();
+ countNode->setValidatorList(validatorList);
+
+ previous->setNextNode(countNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the c operator. Please, change it"));
+ }
+ }
+ break;
+ case Reroll:
+ case RerollUntil:
+ case RerollAndAdd:
+ // Todo: I think that Exploding and Rerolling could share the same code
+ {
+ auto validatorList= readValidatorList(str);
+ QString symbol= m_OptionOp.key(operatorName);
+ if(nullptr != validatorList)
+ {
+ switch(isValidValidator(previous, validatorList))
+ {
+ case Dice::CONDITION_STATE::ALWAYSTRUE:
+ if(operatorName == RerollAndAdd)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Validator is always true for the %1 operator. Please, change it")
+ .arg(symbol));
+ }
+ break;
+ case Dice::CONDITION_STATE::UNREACHABLE:
+ if(operatorName == RerollUntil)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition can't be reached, causing endless loop. Please, "
+ "change the %1 option condition")
+ .arg(symbol));
+ }
+ break;
+ case Dice::CONDITION_STATE::ERROR_STATE:
+ default:
+ break;
+ }
+
+ auto reroll= (operatorName == RerollAndAdd || operatorName == Reroll);
+ auto addingMode= (operatorName == RerollAndAdd);
+ RerollDiceNode* rerollNode= new RerollDiceNode(reroll, addingMode);
+ ExecutionNode* nodeParam= nullptr;
+ if(readParameterNode(str, nodeParam))
+ {
+ rerollNode->setInstruction(nodeParam);
+ }
+ rerollNode->setValidatorList(validatorList);
+ previous->setNextNode(rerollNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the %1 operator. Please, change it").arg(symbol));
+ }
+ }
+ break;
+ case Explode:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE == isValidValidator(previous, validatorList))
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("This condition %1 introduces an endless loop. Please, change it")
+ .arg(validatorList->toString()));
+ }
+ ExplodeDiceNode* explodedNode= new ExplodeDiceNode();
+ explodedNode->setValidatorList(validatorList);
+ previous->setNextNode(explodedNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the e operator. Please, change it"));
+ }
+ }
+ break;
+ case Merge:
+ {
+ MergeNode* mergeNode= new MergeNode();
+ mergeNode->setStartList(&m_startNodes);
+ previous->setNextNode(mergeNode);
+ found= true;
+ }
+ break;
+ case AllSameExplode:
+ {
+ AllSameNode* allSame= new AllSameNode();
+ previous->setNextNode(allSame);
+ found= true;
+ }
+ break;
+ case SwitchCaseOption:
+ {
+ auto scNode= new SwitchCaseNode();
+ found= readSwitchCaseNode(str, scNode);
+ previous->setNextNode(scNode);
+ }
+ break;
+ case TransformOption:
+ {
+ auto scNode= new ReplaceValueNode();
+ found= readReplaceValueNode(str, scNode);
+ previous->setNextNode(scNode);
+ }
+ break;
+ case Bind:
+ {
+ BindNode* bindNode= new BindNode();
+ bindNode->setStartList(&m_startNodes);
+ previous->setNextNode(bindNode);
+ found= true;
+ }
+ break;
+ case Occurences:
+ {
+ qint64 number= 0;
+ auto occNode= new OccurenceCountNode();
+ if(readNumber(str, number))
+ {
+ occNode->setWidth(number);
+ auto validatorList= readValidatorList(str);
+ if(validatorList)
+ {
+ occNode->setValidatorList(validatorList);
+ }
+ else if(readComma(str))
+ {
+ if(readNumber(str, number))
+ {
+ occNode->setHeight(number);
+ }
+ }
+ }
+ previous->setNextNode(occNode);
+ found= true;
+ }
+ break;
+ case Unique:
+ {
+ auto node= new UniqueNode();
+ previous->setNextNode(node);
+ found= true;
+ }
+ break;
+ case Painter:
+ {
+ PainterNode* painter= new PainterNode();
+ if(!readPainterParameter(painter, str))
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Missing parameter for Painter node (p)"));
+ delete painter;
+ }
+ else
+ {
+ previous->setNextNode(painter);
+ found= true;
+ }
+ }
+ break;
+ case ifOperator:
+ {
+ IfNode* nodeif= new IfNode();
+ nodeif->setConditionType(readConditionType(str));
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ ExecutionNode* trueNode= nullptr;
+ ExecutionNode* falseNode= nullptr;
+ if(readIfInstruction(str, trueNode, falseNode))
+ {
+ nodeif->setInstructionTrue(trueNode);
+ nodeif->setInstructionFalse(falseNode);
+ nodeif->setValidatorList(validatorList);
+ previous->setNextNode(nodeif);
+ found= true;
+ }
+ else
+ {
+ delete nodeif;
+ }
+ }
+ else
+ {
+ delete nodeif;
+ }
+ break;
+ }
+ case Split:
+ {
+ SplitNode* splitnode= new SplitNode();
+ previous->setNextNode(splitnode);
+ found= true;
+ }
+ break;
+ case Group:
+ {
+ bool stringResult= readStringResultParameter(str);
+ qint64 groupNumber= 0;
+ if(readNumber(str, groupNumber))
+ {
+ GroupNode* groupNode= new GroupNode(stringResult);
+ groupNode->setGroupValue(groupNumber);
+ previous->setNextNode(groupNode);
+ found= true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return found;
+}
+bool ParsingToolBox::readStringResultParameter(QString& str)
+{
+ if(str.startsWith("s"))
+ {
+ str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+bool ParsingToolBox::readIfInstruction(QString& str, ExecutionNode*& trueNode, ExecutionNode*& falseNode)
+{
+ if(readBlocInstruction(str, trueNode))
+ {
+ if(readBlocInstruction(str, falseNode))
+ {
+ return true;
+ }
+ return true;
+ }
+ return false;
+}
+DiceRollerNode* ParsingToolBox::addRollDiceNode(qint64 faces, ExecutionNode* previous)
+{
+ DiceRollerNode* mydiceRoller= new DiceRollerNode(faces);
+ previous->setNextNode(mydiceRoller);
+ return mydiceRoller;
+}
+ExplodeDiceNode* ParsingToolBox::addExplodeDiceNode(qint64 value, ExecutionNode* previous)
+{
+ ExplodeDiceNode* explodeDiceNode= new ExplodeDiceNode();
+ NumberNode* node= new NumberNode();
+ node->setNumber(value);
+ BooleanCondition* condition= new BooleanCondition();
+ condition->setConditionType(Dice::OnEach);
+ condition->setValueNode(node);
+ condition->setOperator(Dice::CompareOperator::Equal);
+ auto valList= new ValidatorList();
+ valList->setValidators(QList<Validator*>() << condition);
+ auto validity= isValidValidator(previous, valList);
+ explodeDiceNode->setValidatorList(valList);
+ previous->setNextNode(explodeDiceNode);
+ return explodeDiceNode;
+}
+bool ParsingToolBox::readParameterNode(QString& str, ExecutionNode*& node)
+{
+ if(str.startsWith("("))
+ {
+ str= str.remove(0, 1);
+ if(readExpression(str, node))
+ {
+ if(str.startsWith(")"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool ParsingToolBox::readSwitchCaseNode(QString& str, SwitchCaseNode* node)
+{
+ bool res= false;
+ node->setStopAtFirt(ParsingToolBox::readStopAtFirst(str));
+ bool hasInstructionBloc= false;
+ do
+ {
+ auto validator= readValidatorList(str);
+ ExecutionNode* exeNode= nullptr;
+ hasInstructionBloc= readBlocInstruction(str, exeNode);
+ if(hasInstructionBloc)
+ {
+ node->insertCase(exeNode, validator);
+ res= true;
+ }
+
+ } while(hasInstructionBloc);
+
+ return res;
+}
+
+bool ParsingToolBox::readReplaceValueNode(QString& str, ReplaceValueNode* node)
+{
+ bool res= false;
+ bool hasInstructionBloc= false;
+ do
+ {
+ auto validator= readValidatorList(str);
+ ExecutionNode* exeNode= nullptr;
+ hasInstructionBloc= readBlocInstruction(str, exeNode);
+ if(hasInstructionBloc)
+ {
+ node->insertCase(exeNode, validator);
+ res= true;
+ }
+
+ } while(hasInstructionBloc);
+
+ return res;
+}
+
+bool ParsingToolBox::readBlocInstruction(QString& str, ExecutionNode*& resultnode)
+{
+ if(str.startsWith('{'))
+ {
+ str= str.remove(0, 1);
+ ExecutionNode* node= nullptr;
+ Dice::ArithmeticOperator op;
+ ScalarOperatorNode* scalarNode= nullptr;
+ if(readArithmeticOperator(str, op))
+ {
+ scalarNode= new ScalarOperatorNode();
+ scalarNode->setArithmeticOperator(op);
+ }
+ if(readExpression(str, node))
+ {
+ if(str.startsWith('}'))
+ {
+ if(nullptr == scalarNode)
+ {
+ resultnode= node;
+ }
+ else
+ {
+ resultnode= scalarNode;
+ scalarNode->setInternalNode(node);
+ }
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+bool ParsingToolBox::readDice(QString& str, ExecutionNode*& node)
+{
+ DiceOperator currentOperator;
+
+ if(readDiceOperator(str, currentOperator))
+ {
+ if(currentOperator == D)
+ {
+ qint64 max;
+ qint64 min;
+ bool unique= (ParsingToolBox::UNIQUE == readListOperator(str)) ? true : false;
+ Dice::ArithmeticOperator op;
+
+ bool hasOp= readArithmeticOperator(str, op);
+ if(readNumber(str, max))
+ {
+ if(max < 1)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Dice with %1 face(s) does not exist. Please, put a value higher than 0").arg(max));
+ return false;
+ }
+ DiceRollerNode* drNode= new DiceRollerNode(max);
+ drNode->setUnique(unique);
+ if(hasOp)
+ {
+ drNode->setOperator(op);
+ }
+ node= drNode;
+ ExecutionNode* current= drNode;
+ while(readOption(str, current))
+ {
+ current= ParsingToolBox::getLeafNode(current);
+ }
+ return true;
+ }
+ else if(readDiceRange(str, min, max))
+ {
+ DiceRollerNode* drNode= new DiceRollerNode(max, min);
+ drNode->setUnique(unique);
+ if(hasOp)
+ {
+ drNode->setOperator(op);
+ }
+ node= drNode;
+ ExecutionNode* current= drNode;
+ while(readOption(str, current))
+ {
+ current= ParsingToolBox::getLeafNode(current);
+ }
+ return true;
+ }
+ }
+ else if(currentOperator == L)
+ {
+ QStringList list;
+ QList<Range> listRange;
+ ParsingToolBox::LIST_OPERATOR op= readListOperator(str);
+ if(readList(str, list, listRange))
+ {
+ ListSetRollNode* lsrNode= new ListSetRollNode();
+ lsrNode->setRangeList(listRange);
+ if(op == ParsingToolBox::UNIQUE || op == ParsingToolBox::UniqueAndNoComma)
+ {
+ lsrNode->setUnique(true);
+ }
+ if(op == ParsingToolBox::NOCOMMA || op == ParsingToolBox::UniqueAndNoComma)
+ {
+ lsrNode->setNoComma(true);
+ }
+ lsrNode->setListValue(list);
+ node= lsrNode;
+ return true;
+ }
+ else
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr(
+ "List is missing after the L operator. Please, add it (e.g : 1L[sword,spear,gun,arrow])"));
+ }
+ }
+ }
+
+ return false;
+}
+bool ParsingToolBox::readDiceOperator(QString& str, DiceOperator& op)
+{
+ QStringList listKey= m_mapDiceOp.keys();
+ for(const QString& key : qAsConst(listKey))
+ {
+ if(str.startsWith(key, Qt::CaseInsensitive))
+ {
+ str= str.remove(0, key.size());
+ op= m_mapDiceOp.value(key);
+ return true;
+ }
+ }
+ return false;
+}
+QString ParsingToolBox::convertAlias(QString str)
+{
+ for(auto& cmd : m_aliasList)
+ {
+ if(cmd->isEnable())
+ {
+ cmd->resolved(str);
+ }
+ }
+ return str;
+}
+
+bool ParsingToolBox::readCommand(QString& str, ExecutionNode*& node)
+{
+ if(m_commandList.contains(str))
+ {
+ if(str == QLatin1String("help"))
+ {
+ str= str.remove(0, QLatin1String("help").size());
+ HelpNode* help= new HelpNode();
+ if(!m_helpPath.isEmpty())
+ {
+ help->setHelpPath(m_helpPath);
+ }
+ node= help;
+ }
+ else if(str == QLatin1String("la"))
+ {
+ str= str.remove(0, QLatin1String("la").size());
+ node= new ListAliasNode(m_aliasList);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readDiceExpression(QString& str, ExecutionNode*& node)
+{
+ bool returnVal= false;
+
+ ExecutionNode* next= nullptr;
+ if(readDice(str, next))
+ {
+ ExecutionNode* latest= next;
+ while(readOption(str, latest))
+ {
+ while(nullptr != latest->getNextNode())
+ {
+ latest= latest->getNextNode();
+ }
+ }
+
+ node= next;
+ returnVal= true;
+ }
+ else
+ {
+ returnVal= false;
+ }
+ return returnVal;
+}
+
+bool ParsingToolBox::readOperator(QString& str, ExecutionNode* previous)
+{
+ bool result= false;
+ if(str.isEmpty() || nullptr == previous)
+ {
+ return result;
+ }
+
+ Dice::ArithmeticOperator op;
+ if(readArithmeticOperator(str, op))
+ {
+ ScalarOperatorNode* node= new ScalarOperatorNode();
+ node->setArithmeticOperator(op);
+ ExecutionNode* nodeExec= nullptr;
+ if(readExpression(str, nodeExec))
+ {
+ node->setInternalNode(nodeExec);
+ if(nullptr == nodeExec)
+ {
+ delete node;
+ return result;
+ }
+ ExecutionNode* nodeExecOrChild= nodeExec;
+ ExecutionNode* parent= nullptr;
+
+ while((nullptr != nodeExecOrChild) && (node->getPriority() < nodeExecOrChild->getPriority()))
+ {
+ parent= nodeExecOrChild;
+ nodeExecOrChild= nodeExecOrChild->getNextNode();
+ }
+ // management of operator priority
+ if((nullptr != nodeExecOrChild) && (nodeExec != nodeExecOrChild))
+ {
+ // good 1 1 2 ; bad 1 0 4
+ if(nodeExecOrChild->getPriority() >= node->getPriority())
+ {
+ node->setNextNode(nodeExecOrChild);
+ parent->setNextNode(nullptr);
+ }
+ }
+ else if(node->getPriority() >= nodeExec->getPriority())
+ {
+ node->setNextNode(nodeExec->getNextNode());
+ nodeExec->setNextNode(nullptr);
+ }
+
+ // nodeResult = node;
+ previous->setNextNode(node);
+
+ result= true;
+ }
+ else
+ {
+ delete node;
+ }
+ }
+ else
+ {
+ while(readOption(str, previous))
+ {
+ previous= ParsingToolBox::getLeafNode(previous);
+ result= true;
+ }
+ }
+ return result;
+}
+bool ParsingToolBox::readFunction(QString& str, ExecutionNode*& node)
+{
+ for(const auto& kv : m_functionMap)
+ {
+ if(str.startsWith(kv.first))
+ {
+ str= str.remove(0, kv.first.size());
+ switch(kv.second)
+ {
+ case REPEAT:
+ {
+ auto repeaterNode= new RepeaterNode();
+ if(ParsingToolBox::readReaperArguments(repeaterNode, str))
+ {
+ node= repeaterNode;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if(node == nullptr)
+ return false;
+ return true;
+}
+
+bool ParsingToolBox::readNode(QString& str, ExecutionNode*& node)
+{
+ if(str.isEmpty())
+ return false;
+
+ QString key= str.at(0);
+ if(m_nodeActionMap.contains(key))
+ {
+ JumpBackwardNode* jumpNode= new JumpBackwardNode();
+ node= jumpNode;
+ str= str.remove(0, 1);
+ readOption(str, jumpNode);
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readInstructionOperator(QChar c)
+{
+ if(c == ';')
+ {
+ return true;
+ }
+ return false;
+}
+
+void ParsingToolBox::insertAlias(DiceAlias* dice, int i)
+{
+ if(i >= m_aliasList.size())
+ {
+ m_aliasList.insert(i, dice);
+ }
+}
+const QList<DiceAlias*>& ParsingToolBox::getAliases() const
+{
+ return m_aliasList;
+}
+
+QList<DiceAlias*>* ParsingToolBox::aliases()
+{
+ return &m_aliasList;
+}
+
+void ParsingToolBox::setAliases(const QList<DiceAlias*> list)
+{
+ qDeleteAll(m_aliasList);
+ m_aliasList.clear();
+ m_aliasList= list;
+}
+
+std::vector<ExecutionNode*> ParsingToolBox::readInstructionList(QString& str, bool global)
+{
+ if(str.isEmpty())
+ return {};
+
+ std::vector<ExecutionNode*> startNodes;
+
+ bool hasInstruction= false;
+ bool readInstruction= true;
+ while(readInstruction)
+ {
+ ExecutionNode* startNode= nullptr;
+ bool keepParsing= readExpression(str, startNode);
+ if(nullptr != startNode)
+ {
+ hasInstruction= true;
+ startNodes.push_back(startNode);
+ auto latest= startNode;
+ if(keepParsing)
+ {
+ latest= ParsingToolBox::getLeafNode(latest);
+ keepParsing= !str.isEmpty();
+ while(keepParsing)
+ {
+ auto before= str;
+ if(readOperator(str, latest))
+ {
+ latest= ParsingToolBox::getLeafNode(latest);
+ }
+ keepParsing= (!str.isEmpty() && (before != str));
+ }
+ }
+ if(!str.isEmpty() && readInstructionOperator(str[0]))
+ {
+ str= str.remove(0, 1);
+ }
+ else
+ {
+ QString result;
+ QString comment;
+ if(readComment(str, result, comment))
+ {
+ m_comment= result;
+ }
+ readInstruction= false;
+ }
+ }
+ else
+ {
+ readInstruction= false;
+ }
+ }
+ if(global)
+ m_startNodes= startNodes;
+ return startNodes;
+}
+
+SubtituteInfo ParsingToolBox::readVariableFromString(const QString& source, int& start)
+{
+ bool found= false;
+ SubtituteInfo info;
+ int i= start;
+ for(; i >= 0 && !found; --i)
+ {
+ if(source.at(i) == '$')
+ {
+ auto rest= source.mid(i + 1, 1 + start - i);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ auto len= QString::number(number).size() - 1;
+ readSubtitutionParameters(info, rest);
+ info.setLength(info.length() + len);
+ info.setResultIndex(static_cast<int>(number));
+ info.setPosition(i);
+ found= true;
+ }
+ }
+ }
+ start= i;
+ return info;
+}
+
+SubtituteInfo ParsingToolBox::readPlaceHolderFromString(const QString& source, int& start)
+{
+ bool found= false;
+ SubtituteInfo info;
+ int i= start;
+ for(; i >= 0 && !found; --i)
+ {
+ if(source.at(i) == '@')
+ {
+ auto rest= source.mid(i + 1, 1 + start - i);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ auto len= QString::number(number).size() - 1;
+ readSubtitutionParameters(info, rest);
+ info.setLength(info.length() + len);
+ info.setResultIndex(static_cast<int>(number));
+ info.setPosition(i);
+ found= true;
+ }
+ }
+ }
+ start= i;
+ return info;
+}
+
+QString ParsingToolBox::number(qreal value)
+{
+ if(value > 1000000)
+ return QString::number(value, 'f', 20);
+ else
+ return QString::number(value);
+}
+
+ExportedDiceResult ParsingToolBox::finalDiceResultFromInstruction(ExecutionNode* start)
+{
+ ExecutionNode* next= ParsingToolBox::getLeafNode(start);
+ Result* result= next->getResult();
+ ExportedDiceResult nodeResult;
+ std::set<QString> alreadyAdded;
+ while(nullptr != result)
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ QList<HighLightDice> list;
+ quint64 faces= 0;
+ for(auto& die : diceResult->getResultList())
+ {
+ faces= die->getFaces();
+ HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(),
+ die->hasBeenDisplayed(), die->getFaces(), die->getUuid());
+ if(alreadyAdded.find(die->getUuid()) == alreadyAdded.end() && !hlDice.displayed())
+ {
+ list.append(hlDice);
+ alreadyAdded.insert(die->getUuid());
+ }
+ }
+ if(!list.isEmpty())
+ {
+ auto vals= nodeResult.value(faces);
+ vals.append(list);
+ nodeResult.insert(faces, vals);
+ }
+ }
+ /*if(nodeResult.isEmpty())
+ result= result->getPrevious();
+ else*/
+ result= result->getPrevious();
+ }
+ return nodeResult;
+}
+
+ExportedDiceResult ParsingToolBox::allDiceResultFromInstruction(ExecutionNode* start)
+{
+ ExecutionNode* next= ParsingToolBox::getLeafNode(start);
+ Result* result= next->getResult();
+ ExportedDiceResult nodeResult;
+ std::set<QString> alreadyAdded;
+ while(nullptr != result)
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ QList<HighLightDice> list;
+ quint64 faces= 0;
+ for(auto& die : diceResult->getResultList())
+ {
+ faces= die->getFaces();
+ HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(),
+ die->hasBeenDisplayed(), die->getFaces(), die->getUuid());
+ if(alreadyAdded.find(die->getUuid()) == alreadyAdded.end())
+ {
+ list.append(hlDice);
+ alreadyAdded.insert(die->getUuid());
+ }
+ }
+ if(!list.isEmpty())
+ {
+ auto vals= nodeResult.value(faces);
+ vals.append(list);
+ nodeResult.insert(faces, vals);
+ }
+ }
+ result= result->getPrevious();
+ }
+ return nodeResult;
+}
+
+void ParsingToolBox::addResultInJson(QJsonObject& obj, Dice::RESULT_TYPE type, const QString& key, ExecutionNode* start,
+ bool b)
+{
+ auto pair= hasResultOfType(type, start, b);
+ if(pair.first)
+ obj[key]= QJsonValue::fromVariant(pair.second);
+}
+
+void ParsingToolBox::addDiceResultInJson(
+ QJsonObject& obj, ExecutionNode* start,
+ std::function<QString(const QString& value, const QString& color, bool highlighted)> colorize)
+{
+ QJsonArray diceValues;
+ auto result= ParsingToolBox::allDiceResultFromInstruction(start);
+ for(auto listOfList : result.values())
+ {
+ for(auto listDiceResult : listOfList)
+ {
+ for(auto hlDice : listDiceResult)
+ {
+ QJsonObject diceObj;
+ diceObj["face"]= static_cast<qreal>(hlDice.faces());
+ diceObj["color"]= hlDice.color();
+ diceObj["displayed"]= hlDice.displayed();
+ diceObj["string"]= colorize(hlDice.getResultString(), hlDice.color(), hlDice.isHighlighted());
+ diceObj["highlight"]= hlDice.isHighlighted();
+ diceObj["uuid"]= hlDice.uuid();
+ auto val= hlDice.result();
+ if(!val.isEmpty())
+ {
+ diceObj["value"]= std::accumulate(val.begin(), val.end(), 0);
+ if(val.size() > 1)
+ {
+ QJsonArray intValues;
+ std::transform(val.begin(), val.end(), std::back_inserter(intValues),
+ [](qint64 val) { return static_cast<int>(val); });
+ diceObj["subvalues"]= intValues;
+ }
+ }
+ diceValues.append(diceObj);
+ }
+ }
+ }
+ if(!diceValues.isEmpty())
+ obj["diceval"]= diceValues;
+}
+
+SubtituteInfo::SubtituteInfo() {}
+
+bool SubtituteInfo::isValid() const
+{
+ return !(m_position + m_resultIndex < 0);
+}
+
+int SubtituteInfo::length() const
+{
+ return m_length;
+}
+
+void SubtituteInfo::setLength(int length)
+{
+ m_length= length;
+}
+
+int SubtituteInfo::resultIndex() const
+{
+ return m_resultIndex;
+}
+
+void SubtituteInfo::setResultIndex(int valueIndex)
+{
+ m_resultIndex= valueIndex;
+}
+
+int SubtituteInfo::position() const
+{
+ return m_position;
+}
+
+void SubtituteInfo::setPosition(int position)
+{
+ m_position= position;
+}
+
+int SubtituteInfo::digitNumber() const
+{
+ return m_digitNumber;
+}
+
+void SubtituteInfo::setDigitNumber(int digitNumber)
+{
+ m_digitNumber= digitNumber;
+}
+
+int SubtituteInfo::subIndex() const
+{
+ return m_subIndex;
+}
+
+void SubtituteInfo::setSubIndex(int subindex)
+{
+ m_subIndex= subindex;
+}
diff --git a/src/libparser/qmltypesregister.cpp b/src/libparser/qmltypesregister.cpp
new file mode 100644
index 0000000..dbd2ac9
--- /dev/null
+++ b/src/libparser/qmltypesregister.cpp
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include <diceparser_qobject/qmltypesregister.h>
+
+#include <QQmlEngine>
+
+#include <diceparser_qobject/diceroller.h>
+#if !defined(UNIT_TEST) && defined(RCSE)
+#include "field.h"
+#endif
+
+void registerQmlTypes()
+{
+ auto p= new DiceRoller;
+ // Q_UNUSED(p)
+ qmlRegisterType<DiceRoller>("Rolisteam", 1, 0, "DiceRoller");
+#if !defined(UNIT_TEST) && defined(RCSE)
+ qmlRegisterType<FieldController>("Rolisteam", 1, 0, "Field");
+#endif
+ delete p;
+}
diff --git a/src/libparser/range.cpp b/src/libparser/range.cpp
new file mode 100644
index 0000000..39a8f66
--- /dev/null
+++ b/src/libparser/range.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "range.h"
+
+Range::Range() : m_hasEnd(false), m_hasStart(false), m_emptyRange(false) {}
+void Range::setValue(qint64 s, qint64 e)
+{
+ m_start= s;
+ m_end= e;
+
+ m_hasEnd= true;
+ m_hasStart= true;
+}
+
+qint64 Range::hasValid(Die* m, bool recursive, bool unhighlight) const
+{
+ qint64 result= 0;
+ if(recursive)
+ {
+ for(qint64& value : m->getListValue())
+ {
+ if((value >= m_start) && (value <= m_end))
+ {
+ ++result;
+ }
+ }
+ }
+ else if((m->getLastRolledValue() >= m_start) && (m->getLastRolledValue() <= m_end))
+ {
+ ++result;
+ }
+ if((unhighlight) && (result == 0))
+ {
+ m->setHighlighted(false);
+ }
+ return result;
+}
+QString Range::toString()
+{
+ return QStringLiteral("[%1-%2]").arg(m_start).arg(m_end);
+}
+Dice::CONDITION_STATE Range::isValidRangeSize(const std::pair<qint64, qint64>& range) const
+{
+ auto minRange= std::min(m_start, m_end);
+ auto minPossibleValue= std::min(range.first, range.second);
+
+ auto maxRange= std::max(m_start, m_end);
+ auto maxPossibleValue= std::max(range.first, range.second);
+
+ if(minRange == minPossibleValue && maxRange == maxPossibleValue)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else if(maxRange < minPossibleValue || minRange > maxPossibleValue)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else
+ return Dice::CONDITION_STATE::UNREACHABLE;
+}
+void Range::setStart(qint64 start)
+{
+ m_start= start;
+ m_hasStart= true;
+}
+void Range::setEnd(qint64 end)
+{
+ m_end= end;
+ m_hasEnd= true;
+}
+
+bool Range::isFullyDefined() const
+{
+ return (m_hasEnd && m_hasStart);
+}
+qint64 Range::getStart() const
+{
+ return m_start;
+}
+qint64 Range::getEnd() const
+{
+ return m_end;
+}
+void Range::setEmptyRange(bool b)
+{
+ m_emptyRange= b;
+}
+
+bool Range::isEmptyRange()
+{
+ return m_emptyRange;
+}
+Validator* Range::getCopy() const
+{
+ Range* val= new Range();
+ val->setEmptyRange(m_emptyRange);
+ if(m_hasEnd)
+ {
+ val->setEnd(m_end);
+ }
+ if(m_hasStart)
+ {
+ val->setStart(m_start);
+ }
+ return val;
+}
diff --git a/src/libparser/range.h b/src/libparser/range.h
new file mode 100644
index 0000000..276ed55
--- /dev/null
+++ b/src/libparser/range.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef RANGE_H
+#define RANGE_H
+
+#include "validator.h"
+#include <Qt>
+
+/**
+ * @brief The Range class is validator class to check validity between two values.
+ */
+class Range : public Validator
+{
+public:
+ Range();
+ void setValue(qint64, qint64);
+ void setStart(qint64);
+ void setEnd(qint64);
+ virtual qint64 hasValid(Die* b, bool recursive, bool unlight= false) const override;
+
+ virtual QString toString() override;
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override;
+
+ bool isFullyDefined() const;
+ qint64 getStart() const;
+ qint64 getEnd() const;
+
+ void setEmptyRange(bool);
+ bool isEmptyRange();
+
+ virtual Validator* getCopy() const override;
+
+private:
+ qint64 m_start= 0;
+ qint64 m_end= 0;
+ bool m_hasEnd;
+ bool m_hasStart;
+ bool m_emptyRange;
+};
+
+#endif // RANGE_H
diff --git a/src/libparser/result/diceresult.cpp b/src/libparser/result/diceresult.cpp
new file mode 100644
index 0000000..31e316b
--- /dev/null
+++ b/src/libparser/result/diceresult.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "diceresult.h"
+#include <QDebug>
+
+DiceResult::DiceResult()
+{
+ m_resultTypes= (static_cast<int>(Dice::RESULT_TYPE::DICE_LIST) | static_cast<int>(Dice::RESULT_TYPE::SCALAR));
+ m_homogeneous= true;
+}
+void DiceResult::insertResult(Die* die)
+{
+ m_diceValues.append(die);
+}
+QList<Die*>& DiceResult::getResultList()
+{
+ return m_diceValues;
+}
+bool DiceResult::isHomogeneous() const
+{
+ return m_homogeneous;
+}
+void DiceResult::setHomogeneous(bool b)
+{
+ m_homogeneous= b;
+}
+
+void DiceResult::setResultList(QList<Die*> list)
+{
+ m_diceValues.erase(
+ std::remove_if(m_diceValues.begin(), m_diceValues.end(), [list](Die* die) { return list.contains(die); }),
+ m_diceValues.end());
+
+ qDeleteAll(m_diceValues.begin(), m_diceValues.end());
+ m_diceValues.clear();
+ m_diceValues << list;
+}
+DiceResult::~DiceResult()
+{
+ if(!m_diceValues.isEmpty())
+ {
+ qDeleteAll(m_diceValues.begin(), m_diceValues.end());
+ m_diceValues.clear();
+ }
+}
+QVariant DiceResult::getResult(Dice::RESULT_TYPE type)
+{
+ switch(type)
+ {
+ case Dice::RESULT_TYPE::SCALAR:
+ {
+ return getScalarResult();
+ }
+ case Dice::RESULT_TYPE::DICE_LIST:
+ {
+ return QVariant::fromValue(m_diceValues);
+ }
+ default:
+ break;
+ }
+ return QVariant();
+}
+bool DiceResult::contains(Die* die, const std::function<bool(const Die*, const Die*)> equal)
+{
+ for(auto& value : m_diceValues)
+ {
+ if(equal(value, die))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+qreal DiceResult::getScalarResult()
+{
+ if(m_diceValues.size() == 1)
+ {
+ return m_diceValues[0]->getValue();
+ }
+ else
+ {
+ qint64 scalar= 0;
+ int i= 0;
+ for(auto& tmp : m_diceValues)
+ {
+ if(i > 0)
+ {
+ switch(m_operator)
+ {
+ case Dice::ArithmeticOperator::PLUS:
+ scalar+= tmp->getValue();
+ break;
+ case Dice::ArithmeticOperator::MULTIPLICATION:
+ scalar*= tmp->getValue();
+ break;
+ case Dice::ArithmeticOperator::MINUS:
+ scalar-= tmp->getValue();
+ break;
+ case Dice::ArithmeticOperator::POW:
+ scalar= static_cast<int>(pow(static_cast<double>(scalar), static_cast<double>(tmp->getValue())));
+ break;
+ case Dice::ArithmeticOperator::DIVIDE:
+ case Dice::ArithmeticOperator::INTEGER_DIVIDE:
+ if(tmp->getValue() != 0)
+ {
+ scalar/= tmp->getValue();
+ }
+ else
+ {
+ /// @todo Error cant divide by 0. Must be displayed.
+ }
+ break;
+ }
+ }
+ else
+ {
+ scalar= tmp->getValue();
+ }
+ ++i;
+ }
+ return scalar;
+ }
+}
+
+Dice::ArithmeticOperator DiceResult::getOperator() const
+{
+ return m_operator;
+}
+
+void DiceResult::clear()
+{
+ m_diceValues.clear();
+}
+
+void DiceResult::setOperator(const Dice::ArithmeticOperator& dieOperator)
+{
+ m_operator= dieOperator;
+}
+QString DiceResult::toString(bool wl)
+{
+ QStringList scalarSum;
+ for(auto& die : m_diceValues)
+ {
+ scalarSum << QString::number(die->getValue());
+ }
+ if(wl)
+ {
+ return QStringLiteral("%3 [label=\"DiceResult Value %1 dice %2\"]")
+ .arg(QString::number(getScalarResult()), scalarSum.join('_'), m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+Result* DiceResult::getCopy() const
+{
+ auto copy= new DiceResult();
+ copy->setHomogeneous(m_homogeneous);
+ copy->setOperator(m_operator);
+ copy->m_id= m_id;
+ QList<Die*> list;
+ for(auto die : m_diceValues)
+ {
+ auto newdie= new Die(*die);
+ newdie->setDisplayed(false);
+ // die->displayed();
+ list.append(newdie);
+ }
+ copy->setResultList(list);
+ copy->setPrevious(getPrevious());
+ return copy;
+}
diff --git a/src/libparser/result/diceresult.h b/src/libparser/result/diceresult.h
new file mode 100644
index 0000000..1b35b7e
--- /dev/null
+++ b/src/libparser/result/diceresult.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef DICERESULT_H
+#define DICERESULT_H
+#include <QList>
+#include <functional>
+
+#include "diceparser/diceparserhelper.h"
+#include "die.h"
+#include "result.h"
+/**
+ * @brief The DiceResult class
+ */
+class DiceResult : public Result
+{
+public:
+ /**
+ * @brief DiceResult
+ */
+ DiceResult();
+ /**
+ * @brief ~DiceResult
+ */
+ virtual ~DiceResult() override;
+
+ /**
+ * @brief getResultList
+ * @return
+ */
+ virtual QList<Die*>& getResultList();
+ /**
+ * @brief insertResult
+ */
+ virtual void insertResult(Die*);
+
+ /**
+ * @brief setResultList
+ * @param list
+ */
+ virtual void setResultList(QList<Die*> list);
+
+ /**
+ * @brief getScalar
+ * @return
+ */
+ virtual QVariant getResult(Dice::RESULT_TYPE) override;
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool wl) override;
+ /**
+ * @brief isHomogeneous
+ */
+ virtual bool isHomogeneous() const;
+ /**
+ * @brief setHomogeneous
+ */
+ virtual void setHomogeneous(bool);
+
+ Dice::ArithmeticOperator getOperator() const;
+ void setOperator(const Dice::ArithmeticOperator& dieOperator);
+ bool contains(Die* die, const std::function<bool(const Die*, const Die*)> equal);
+
+ void clear() override;
+
+ virtual Result* getCopy() const override;
+
+protected:
+ qreal getScalarResult();
+
+protected:
+ QList<Die*> m_diceValues;
+ bool m_homogeneous;
+ Dice::ArithmeticOperator m_operator{Dice::ArithmeticOperator::PLUS};
+};
+Q_DECLARE_METATYPE(QList<Die*>)
+#endif // DICERESULT_H
diff --git a/src/libparser/result/result.cpp b/src/libparser/result/result.cpp
new file mode 100644
index 0000000..ca410b3
--- /dev/null
+++ b/src/libparser/result/result.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "result.h"
+#include <QUuid>
+
+Result::Result()
+ : m_resultTypes(static_cast<int>(Dice::RESULT_TYPE::NONE))
+ , m_id(QString("\"%1\"").arg(QUuid::createUuid().toString()))
+ , m_previous(nullptr)
+{
+}
+Result::~Result() {}
+
+Result* Result::getPrevious() const
+{
+ return m_previous;
+}
+
+void Result::setPrevious(Result* p)
+{
+ Q_ASSERT(p != this);
+ m_previous= p;
+}
+
+bool Result::isStringResult() const
+{
+ return false;
+}
+void Result::clear() {}
+bool Result::hasResultOfType(Dice::RESULT_TYPE type) const
+{
+ return (m_resultTypes & static_cast<int>(type));
+}
+void Result::generateDotTree(QString& s)
+{
+ auto str= toString(true);
+ if(s.contains(str))
+ return;
+ s.append(str);
+ s.append(";\n");
+
+ if(nullptr != m_previous)
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append(m_previous->toString(false));
+ s.append("[label=\"previousResult\"]\n");
+ m_previous->generateDotTree(s);
+ }
+ else
+ {
+ s.append(toString(false));
+ s.append(" -> ");
+ s.append("nullptr");
+ s.append(" [label=\"previousResult\", shape=\"box\"];\n");
+ }
+}
+
+QString Result::getId() const
+{
+ return m_id;
+}
+
+QString Result::getStringResult() const
+{
+ return {};
+}
diff --git a/src/libparser/result/result.h b/src/libparser/result/result.h
new file mode 100644
index 0000000..4432682
--- /dev/null
+++ b/src/libparser/result/result.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef RESULT_H
+#define RESULT_H
+
+#include <QString>
+#include <QVariant>
+#include <diceparser/diceparserhelper.h>
+/**
+ * @brief The Result class
+ */
+class Result
+{
+public:
+ /**
+ * @brief Result
+ */
+ Result();
+ /**
+ * @brief ~Result
+ */
+ virtual ~Result();
+
+ /**
+ * @brief isScalar
+ * @return
+ */
+ virtual bool hasResultOfType(Dice::RESULT_TYPE) const;
+ /**
+ * @brief getScalar
+ * @return
+ */
+ virtual QVariant getResult(Dice::RESULT_TYPE)= 0;
+ /**
+ * @brief getPrevious
+ * @return
+ */
+ virtual Result* getPrevious() const;
+ /**
+ * @brief setPrevious
+ */
+ virtual void setPrevious(Result*);
+ /**
+ * @brief isStringResult
+ * @return
+ */
+ virtual bool isStringResult() const;
+
+ virtual void clear();
+
+ /**
+ * @brief getStringResult
+ * @return
+ */
+ virtual QString getStringResult() const;
+ /**
+ * @brief generateDotTree
+ */
+ void generateDotTree(QString&);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool wl)= 0;
+ virtual Result* getCopy() const= 0;
+
+ QString getId() const;
+
+protected:
+ int m_resultTypes; /// @brief
+ QString m_id;
+
+private:
+ Result* m_previous= nullptr; /// @brief
+};
+
+#endif // RESULT_H
diff --git a/src/libparser/result/scalarresult.cpp b/src/libparser/result/scalarresult.cpp
new file mode 100644
index 0000000..dcbaa61
--- /dev/null
+++ b/src/libparser/result/scalarresult.cpp
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "scalarresult.h"
+
+ScalarResult::ScalarResult()
+{
+ m_resultTypes= static_cast<int>(Dice::RESULT_TYPE::SCALAR);
+}
+
+void ScalarResult::setValue(qreal i)
+{
+ m_value= i;
+}
+QVariant ScalarResult::getResult(Dice::RESULT_TYPE type)
+{
+ if(Dice::RESULT_TYPE::SCALAR == type)
+ {
+ return m_value;
+ }
+ else
+ return {};
+}
+Result* ScalarResult::getCopy() const
+{
+ auto copy= new ScalarResult();
+ copy->setValue(m_value);
+ return copy;
+}
+QString ScalarResult::toString(bool wl)
+{
+ if(wl)
+ {
+ return QString("%2 [label=\"ScalarResult %1\"]").arg(m_value).arg(m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
diff --git a/src/libparser/result/scalarresult.h b/src/libparser/result/scalarresult.h
new file mode 100644
index 0000000..73fe73b
--- /dev/null
+++ b/src/libparser/result/scalarresult.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SCALARRESULT_H
+#define SCALARRESULT_H
+
+#include "result.h"
+#include <Qt>
+
+/**
+ * @brief The ScalarResult class is used to store scalar result by many ExecutionNode.
+ */
+class ScalarResult : public Result
+{
+public:
+ /**
+ * @brief ScalarResult
+ */
+ ScalarResult();
+ /**
+ * @brief getResult
+ * @return
+ */
+ virtual QVariant getResult(Dice::RESULT_TYPE);
+ /**
+ * @brief setValue
+ * @param i
+ */
+ void setValue(qreal i);
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString(bool);
+ virtual Result* getCopy() const;
+
+private:
+ qreal m_value= 0;
+};
+
+#endif // SCALARRESULT_H
diff --git a/src/libparser/result/stringresult.cpp b/src/libparser/result/stringresult.cpp
new file mode 100644
index 0000000..113c22c
--- /dev/null
+++ b/src/libparser/result/stringresult.cpp
@@ -0,0 +1,117 @@
+#include "stringresult.h"
+#include <QDebug>
+
+StringResult::StringResult()
+{
+ m_highlight= true;
+ m_resultTypes= static_cast<int>(Dice::RESULT_TYPE::STRING);
+}
+void StringResult::addText(QString text)
+{
+ m_value.append(text);
+}
+StringResult::~StringResult() {}
+bool StringResult::hasResultOfType(Dice::RESULT_TYPE resultType) const
+{
+ bool val= false;
+
+ switch(resultType)
+ {
+ case Dice::RESULT_TYPE::STRING:
+ val= !isDigitOnly();
+ break;
+ case Dice::RESULT_TYPE::SCALAR:
+ val= isDigitOnly();
+ break;
+ case Dice::RESULT_TYPE::DICE_LIST:
+ val= (isDigitOnly() && m_value.size() > 1);
+ break;
+ default:
+ break;
+ }
+ return val;
+}
+
+void StringResult::setNoComma(bool b)
+{
+ m_commaSeparator= !b;
+}
+
+QString StringResult::getText() const
+{
+ return m_commaSeparator ? m_value.join(",") : m_value.join(QString());
+}
+
+QVariant StringResult::getResult(Dice::RESULT_TYPE type)
+{
+ switch(type)
+ {
+ case Dice::RESULT_TYPE::STRING:
+ return getText();
+ case Dice::RESULT_TYPE::SCALAR:
+ return getScalarResult();
+ default:
+ return QVariant();
+ }
+}
+QString StringResult::toString(bool wl)
+{
+ if(wl)
+ {
+ return QString("%2 [label=\"StringResult_value_%1\"]").arg(getText().replace("%", "_"), m_id);
+ }
+ else
+ {
+ return m_id;
+ }
+}
+void StringResult::setHighLight(bool b)
+{
+ m_highlight= b;
+}
+
+bool StringResult::hasHighLight() const
+{
+ return m_highlight;
+}
+
+void StringResult::finished()
+{
+ if(isDigitOnly())
+ {
+ std::for_each(m_value.begin(), m_value.end(), [this](const QString& str) {
+ auto die= new Die();
+ die->setMaxValue(m_stringCount);
+ die->setValue(str.toInt());
+ insertResult(die);
+ });
+ }
+}
+
+void StringResult::setStringCount(int count)
+{
+ m_stringCount= count;
+}
+
+bool StringResult::isDigitOnly() const
+{
+ return std::all_of(m_value.begin(), m_value.end(), [](const QString& str) {
+ bool ok= false;
+ str.toInt(&ok);
+ return ok;
+ });
+}
+
+Result* StringResult::getCopy() const
+{
+ auto copy= new StringResult();
+ copy->setPrevious(getPrevious());
+ copy->setHighLight(m_highlight);
+ std::for_each(m_value.begin(), m_value.end(), [copy](const QString& str) { copy->addText(str); });
+ return copy;
+}
+
+QString StringResult::getStringResult() const
+{
+ return getText();
+}
diff --git a/src/libparser/result/stringresult.h b/src/libparser/result/stringresult.h
new file mode 100644
index 0000000..b0ca539
--- /dev/null
+++ b/src/libparser/result/stringresult.h
@@ -0,0 +1,45 @@
+#ifndef STRINGRESULT_H
+#define STRINGRESULT_H
+
+#include "diceresult.h"
+#include <QString>
+/**
+ * @brief The StringResult class stores command result for String.
+ */
+
+class StringResult : public DiceResult
+{
+public:
+ /**
+ * @brief StringResult
+ */
+ StringResult();
+ /**
+ * @brief StringResult
+ */
+ virtual ~StringResult() override;
+ void addText(QString text);
+ void finished();
+ QString getText() const;
+ virtual QVariant getResult(Dice::RESULT_TYPE) override;
+ virtual QString toString(bool) override;
+
+ virtual void setHighLight(bool);
+ virtual bool hasHighLight() const;
+ virtual bool hasResultOfType(Dice::RESULT_TYPE resultType) const override;
+ virtual Result* getCopy() const override;
+
+ bool isDigitOnly() const;
+
+ void setStringCount(int count);
+ QString getStringResult() const override;
+ void setNoComma(bool b);
+
+private:
+ QStringList m_value;
+ bool m_highlight= true;
+ int m_stringCount= 0;
+ bool m_commaSeparator= true;
+};
+
+#endif // STRINGRESULT_H
diff --git a/src/libparser/validator.cpp b/src/libparser/validator.cpp
new file mode 100644
index 0000000..201574b
--- /dev/null
+++ b/src/libparser/validator.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "validator.h"
+
+Validator::Validator() {}
+Validator::~Validator() {}
+
+template <typename Functor>
+qint64 Validator::onEach(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ qint64 result= 0;
+ std::for_each(b.begin(), b.end(), [this, recursive, unlight, functor, &result](Die* die) {
+ if(hasValid(die, recursive, unlight))
+ {
+ ++result;
+ functor(die, recursive, unlight);
+ }
+ });
+ return result;
+}
+
+template <typename Functor>
+qint64 Validator::onEachValue(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ qint64 result= 0;
+ std::for_each(b.begin(), b.end(), [this, recursive, unlight, functor, &result](Die* die) {
+ if(hasValid(die, recursive, unlight))
+ {
+ ++result;
+ functor(die, recursive, unlight);
+ }
+ });
+ return result;
+}
+
+template <typename Functor>
+qint64 Validator::oneOfThem(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ auto oneOfThem= std::any_of(b.begin(), b.end(),
+ [this, recursive, unlight](Die* die) { return hasValid(die, recursive, unlight); });
+ if(oneOfThem)
+ functor(recursive, unlight);
+ return oneOfThem ? 1 : 0;
+}
+
+template <typename Functor>
+qint64 Validator::allOfThem(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ auto all= std::all_of(b.begin(), b.end(),
+ [this, recursive, unlight](Die* die) { return hasValid(die, recursive, unlight); });
+ if(all)
+ functor(recursive, unlight);
+ return all ? 1 : 0;
+}
+
+template <typename Functor>
+qint64 Validator::onScalar(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ qint64 result= 0;
+ for(const auto& die : b)
+ {
+ result+= die->getValue();
+ }
+ Die die;
+ die.setValue(result);
+ if(hasValid(&die, recursive, unlight))
+ {
+ functor(recursive, unlight);
+ return 1;
+ }
+ return 0;
+}
+
+const std::set<qint64>& Validator::getPossibleValues(const std::pair<qint64, qint64>&)
+{
+ return m_values;
+}
+
+template <typename Functor>
+qint64 Validator::validResult(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const
+{
+ qint64 result;
+ switch(m_conditionType)
+ {
+ case Dice::OnEach:
+ result= onEach(b, recursive, unlight, functor);
+ break;
+ case Dice::OnEachValue:
+ result= onEachValue(b, recursive, unlight, functor);
+ break;
+ case Dice::OneOfThem:
+ result= oneOfThem(b, recursive, unlight, functor);
+ break;
+ case Dice::AllOfThem:
+ result= allOfThem(b, recursive, unlight, functor);
+ break;
+ case Dice::OnScalar:
+ result= onScalar(b, recursive, unlight, functor);
+ break;
+ }
+ return result;
+}
+
+Dice::ConditionType Validator::getConditionType() const
+{
+ return m_conditionType;
+}
+
+void Validator::setConditionType(const Dice::ConditionType& conditionType)
+{
+ m_conditionType= conditionType;
+}
diff --git a/src/libparser/validator.h b/src/libparser/validator.h
new file mode 100644
index 0000000..ca15f67
--- /dev/null
+++ b/src/libparser/validator.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef VALIDATOR_H
+#define VALIDATOR_H
+
+#include <diceparser/diceparserhelper.h>
+
+#include "die.h"
+#include <QString>
+#include <Qt>
+#include <set>
+/**
+ * @brief The Validator class is an abstract class for checking the validity of dice for some
+ * operator.
+ */
+// template <Dice::ConditionType C>
+class Validator
+{
+public:
+ /**
+ * @brief Validator
+ */
+ Validator();
+ /**
+ * @brief ~Validator
+ */
+ virtual ~Validator();
+ /**
+ * @brief hasValid
+ * @param b
+ * @param recursive
+ * @param unlight
+ * @return
+ */
+ virtual qint64 hasValid(Die* b, bool recursive, bool unlight= false) const= 0;
+ /**
+ * @brief toString
+ * @return
+ */
+ virtual QString toString()= 0;
+ /**
+ * @brief getValidRangeSize
+ * @param faces
+ * @return
+ */
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const= 0;
+ /**
+ * @brief getCopy
+ * @return return a copy of this validator
+ */
+ virtual Validator* getCopy() const= 0;
+ /**
+ * @brief getPossibleValues
+ * @param range
+ * @return
+ */
+ virtual const std::set<qint64>& getPossibleValues(const std::pair<qint64, qint64>& range);
+ /**
+ * @brief validResult
+ * @param b
+ * @param recursive
+ * @param unlight
+ * @return
+ */
+ template <typename Functor>
+ qint64 validResult(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+
+ Dice::ConditionType getConditionType() const;
+ void setConditionType(const Dice::ConditionType& conditionType);
+
+protected:
+ template <typename Functor>
+ qint64 onEach(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+ template <typename Functor>
+ qint64 onEachValue(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+ template <typename Functor>
+ qint64 oneOfThem(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+ template <typename Functor>
+ qint64 allOfThem(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+ template <typename Functor>
+ qint64 onScalar(const std::vector<Die*>& b, bool recursive, bool unlight, Functor functor) const;
+
+protected:
+ std::set<qint64> m_values;
+ Dice::ConditionType m_conditionType= Dice::OnEach;
+};
+
+#endif // VALIDATOR_H
diff --git a/src/libparser/validatorlist.cpp b/src/libparser/validatorlist.cpp
new file mode 100644
index 0000000..f1d1ba4
--- /dev/null
+++ b/src/libparser/validatorlist.cpp
@@ -0,0 +1,453 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "validatorlist.h"
+
+#include "result/diceresult.h"
+#include "result/result.h"
+#include "validator.h"
+#include <QDebug>
+#include <utility>
+
+void mergeResultsAsAND(const ValidatorResult& diceList, ValidatorResult& result)
+{
+ ValidatorResult val;
+ for(auto dice : diceList.validDice())
+ {
+ if(result.contains(dice.first) || diceList.allTrue())
+ val.appendValidDice(dice.first, dice.second);
+ }
+ result= val;
+ result.setAllTrue(diceList.allTrue() & result.allTrue());
+}
+
+void mergeResultsAsExeclusiveOR(const ValidatorResult& diceList, ValidatorResult& result)
+{
+ ValidatorResult val;
+ for(auto dice : diceList.validDice())
+ {
+ if(!result.contains(dice.first))
+ val.appendValidDice(dice.first, dice.second);
+ }
+ result= val;
+ result.setAllTrue(diceList.allTrue() ^ result.allTrue());
+}
+
+DiceResult* getDiceResult(Result* result)
+{
+ auto dice= dynamic_cast<DiceResult*>(result);
+ if(nullptr == dice)
+ {
+ auto value= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ dice= new DiceResult();
+ auto die= new Die();
+ die->setValue(value);
+ dice->insertResult(die);
+ qWarning("Error, no dice result");
+ // TODO: manage error here.
+ }
+ return dice;
+}
+
+//////////////////////////////////
+/// \brief ValidatorResult::ValidatorResult
+///
+///
+///
+/// ////////////////////////////////
+ValidatorResult::ValidatorResult() {}
+
+const std::vector<std::pair<Die*, qint64>>& ValidatorResult::validDice() const
+{
+ return m_validDice;
+}
+
+std::vector<std::pair<Die*, qint64>>& ValidatorResult::validDiceRef()
+{
+ return m_validDice;
+}
+
+void ValidatorResult::appendValidDice(Die* die, qint64 sum)
+{
+ m_validDice.push_back(std::make_pair(die, sum));
+}
+
+void ValidatorResult::setAllTrue(bool allTrue)
+{
+ m_allTrue= allTrue;
+}
+
+bool ValidatorResult::allTrue() const
+{
+ return m_allTrue;
+}
+
+bool ValidatorResult::contains(Die* die)
+{
+ auto it= std::find_if(m_validDice.begin(), m_validDice.end(),
+ [die](const std::pair<Die*, qint64>& pair) { return pair.first == die; });
+
+ return it != m_validDice.end();
+}
+
+////////////////////////////////////
+/// \brief ValidatorList::ValidatorList
+///***
+///
+////////////////////////////////////
+
+ValidatorList::ValidatorList() {}
+
+ValidatorList::~ValidatorList()
+{
+ qDeleteAll(m_validatorList);
+}
+qint64 ValidatorList::hasValid(Die* b, bool recursive, bool unhighlight) const
+{
+ int i= 0;
+ qint64 sum= 0;
+ bool highLight= false;
+ for(auto& validator : m_validatorList)
+ {
+ qint64 val= validator->hasValid(b, recursive, unhighlight);
+ if(i == 0)
+ {
+ sum= val;
+ if(b->isHighlighted())
+ {
+ highLight= b->isHighlighted();
+ }
+ }
+ else
+ {
+ switch(m_operators.at(i - 1))
+ {
+ case Dice::LogicOperation::OR:
+ sum|= val;
+
+ if(highLight)
+ {
+ b->setHighlighted(highLight);
+ }
+ break;
+ case Dice::LogicOperation::EXCLUSIVE_OR:
+ sum^= val; /// @todo may required to be done by hand
+ break;
+ case Dice::LogicOperation::AND:
+ sum&= val;
+ break;
+ default:
+ break;
+ }
+ }
+ ++i;
+ }
+
+ return sum;
+}
+
+QString ValidatorList::toString()
+{
+ QString str= "";
+ /*switch (m_operator)
+ {
+ case Equal:
+ str.append("=");
+ break;
+ case GreaterThan:
+ str.append(">");
+ break;
+ case LesserThan:
+ str.append("<");
+ break;
+ case GreaterOrEqual:
+ str.append(">=");
+ break;
+ case LesserOrEqual:
+ str.append("<=");
+ break;
+ }
+ return QString("[%1%2]").arg(str).arg(m_value);*/
+ return str;
+}
+namespace
+{
+Dice::CONDITION_STATE testAND(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == Dice::CONDITION_STATE::UNREACHABLE || current == Dice::CONDITION_STATE::UNREACHABLE)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(before == Dice::CONDITION_STATE::ALWAYSTRUE && current == Dice::CONDITION_STATE::ALWAYSTRUE)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testOR(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == Dice::CONDITION_STATE::UNREACHABLE && current == Dice::CONDITION_STATE::UNREACHABLE)
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if(before == Dice::CONDITION_STATE::ALWAYSTRUE || current == Dice::CONDITION_STATE::ALWAYSTRUE)
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+
+Dice::CONDITION_STATE testXOR(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current)
+{
+ if(before == current
+ && (before == Dice::CONDITION_STATE::UNREACHABLE || before == Dice::CONDITION_STATE::ALWAYSTRUE))
+ return Dice::CONDITION_STATE::UNREACHABLE;
+ else if((before != current)
+ && (before == Dice::CONDITION_STATE::ALWAYSTRUE || before == Dice::CONDITION_STATE::UNREACHABLE)
+ && (before != Dice::CONDITION_STATE::REACHABLE || current != Dice::CONDITION_STATE::REACHABLE))
+ return Dice::CONDITION_STATE::ALWAYSTRUE;
+ else
+ return Dice::CONDITION_STATE::REACHABLE;
+}
+} // namespace
+
+Dice::CONDITION_STATE ValidatorList::isValidRangeSize(const std::pair<qint64, qint64>& range) const
+{
+ std::vector<Dice::CONDITION_STATE> vec;
+ std::transform(m_validatorList.begin(), m_validatorList.end(), std::back_inserter(vec),
+ [range](Validator* validator) -> Dice::CONDITION_STATE
+ { return validator->isValidRangeSize(range); });
+
+ auto itError= std::find(vec.begin(), vec.end(), Dice::CONDITION_STATE::ERROR_STATE);
+
+ if(vec.size() == 1)
+ return vec.front();
+
+ if((static_cast<int>(vec.size()) != m_operators.size() + 1) || (itError != vec.end()))
+ {
+ return Dice::CONDITION_STATE::ERROR_STATE;
+ }
+
+ std::size_t i= 0;
+ Dice::CONDITION_STATE val= Dice::CONDITION_STATE::ERROR_STATE;
+ for(const auto& op : m_operators)
+ {
+ auto currentState= vec[i + 1];
+ if(i == 0)
+ {
+ val= vec[i];
+ }
+ switch(op)
+ {
+ case Dice::LogicOperation::OR:
+ val= testAND(val, currentState);
+ break;
+ case Dice::LogicOperation::EXCLUSIVE_OR:
+ val= testOR(val, currentState);
+ break;
+ case Dice::LogicOperation::AND:
+ val= testXOR(val, currentState);
+ break;
+ case Dice::LogicOperation::NONE:
+ val= Dice::CONDITION_STATE::ERROR_STATE;
+ break;
+ }
+
+ ++i;
+ }
+ return val;
+}
+
+void ValidatorList::setOperationList(const QVector<Dice::LogicOperation>& m)
+{
+ m_operators= m;
+}
+
+void ValidatorList::setValidators(const QList<Validator*>& valids)
+{
+ qDeleteAll(m_validatorList);
+ m_validatorList= valids;
+}
+
+void ValidatorList::validResult(Result* result, bool recursive, bool unlight,
+ std::function<void(Die*, qint64)> functor) const
+{
+ std::vector<ValidatorResult> validityData;
+ for(auto& validator : m_validatorList)
+ {
+ ValidatorResult validResult;
+ switch(validator->getConditionType())
+ {
+ case Dice::OnScalar:
+ {
+ Die die;
+ auto scalar= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt();
+ die.insertRollValue(scalar);
+ if(validator->hasValid(&die, recursive, unlight))
+ {
+ validResult.setAllTrue(true);
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ break;
+
+ if(m_validatorList.size() > 1)
+ {
+ for(auto const& die : qAsConst(diceResult->getResultList()))
+ {
+ validResult.appendValidDice(die, die->getValue());
+ }
+ }
+ else
+ {
+ validResult.appendValidDice(new Die(die), die.getValue());
+ }
+ }
+ }
+ break;
+ case Dice::OnEach:
+ {
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ break;
+ for(auto const& die : qAsConst(diceResult->getResultList()))
+ {
+ auto score= validator->hasValid(die, recursive, unlight);
+ if(score)
+ {
+ validResult.appendValidDice(die, score);
+ }
+ }
+ }
+ break;
+ case Dice::OnEachValue:
+ {
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ break;
+ for(auto const& die : qAsConst(diceResult->getResultList()))
+ {
+ auto score= validator->hasValid(die, recursive, unlight);
+ if(score)
+ {
+ validResult.appendValidDice(die, score);
+ }
+ }
+ }
+ break;
+ case Dice::AllOfThem:
+ {
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ break;
+ auto diceList= diceResult->getResultList();
+ auto all= std::all_of(diceList.begin(), diceList.end(),
+ [validator, recursive, unlight](Die* die)
+ { return validator->hasValid(die, recursive, unlight); });
+ if(all)
+ {
+ validResult.setAllTrue(true);
+ for(auto die : qAsConst(diceResult->getResultList()))
+ {
+ validResult.appendValidDice(die, die->getValue());
+ }
+ }
+ }
+ break;
+ case Dice::OneOfThem:
+ {
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ break;
+ auto diceList= diceResult->getResultList();
+ auto any= std::any_of(diceList.begin(), diceList.end(),
+ [validator, recursive, unlight](Die* die)
+ { return validator->hasValid(die, recursive, unlight); });
+ if(any)
+ {
+ validResult.setAllTrue(true);
+ for(auto die : qAsConst(diceResult->getResultList()))
+ {
+ validResult.appendValidDice(die, die->getValue());
+ }
+ }
+ }
+ }
+ validityData.push_back(validResult);
+ }
+ if(validityData.empty())
+ return;
+
+ int i= 0;
+ ValidatorResult finalResult;
+
+ for(const auto& vec : validityData)
+ {
+ auto diceList= vec.validDice();
+ if(i == 0)
+ {
+ std::copy(diceList.begin(), diceList.end(), std::back_inserter(finalResult.validDiceRef()));
+ }
+ else
+ {
+ auto id= i - 1;
+ if(m_operators.size() <= id)
+ continue;
+
+ auto op= m_operators.at(id);
+ switch(op)
+ {
+ case Dice::LogicOperation::OR:
+ std::copy(diceList.begin(), diceList.end(), std::back_inserter(finalResult.validDiceRef()));
+ break;
+ case Dice::LogicOperation::AND:
+ mergeResultsAsAND(vec, finalResult);
+ break;
+ case Dice::LogicOperation::EXCLUSIVE_OR:
+ mergeResultsAsExeclusiveOR(vec, finalResult);
+ break;
+ case Dice::LogicOperation::NONE:
+ break;
+ }
+ }
+
+ ++i;
+ }
+
+ if(finalResult.allTrue())
+ {
+ DiceResult* diceResult= getDiceResult(result);
+ if(nullptr == diceResult)
+ return;
+ auto diceList= diceResult->getResultList();
+ std::transform(diceList.begin(), diceList.end(), std::back_inserter(finalResult.validDiceRef()),
+ [](Die* die) {
+ return std::pair<Die*, qint64>({die, 0});
+ });
+ }
+
+ for(auto die : finalResult.validDice())
+ {
+ functor(die.first, die.second);
+ }
+}
+
+ValidatorList* ValidatorList::getCopy() const
+{
+ ValidatorList* val= new ValidatorList();
+ val->setOperationList(m_operators);
+ val->setValidators(m_validatorList);
+ return val;
+}
diff --git a/src/libparser/validatorlist.h b/src/libparser/validatorlist.h
new file mode 100644
index 0000000..ad2c9d4
--- /dev/null
+++ b/src/libparser/validatorlist.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * http://www.rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef VALIDATORLIST_H
+#define VALIDATORLIST_H
+
+#include <QList>
+#include <QString>
+#include <QVector>
+#include <Qt>
+
+#include <diceparser/diceparserhelper.h>
+#include <functional>
+
+class Validator;
+class Die;
+class Result;
+
+class ValidatorResult
+{
+
+public:
+ ValidatorResult();
+
+ const std::vector<std::pair<Die*, qint64>>& validDice() const;
+ std::vector<std::pair<Die*, qint64>>& validDiceRef();
+ void setValidDice(const std::vector<std::pair<Die*, qint64>>& pairs);
+ void appendValidDice(Die* die, qint64 sum);
+
+ void setAllTrue(bool allTrue);
+ bool allTrue() const;
+
+ bool contains(Die* die);
+
+private:
+ std::vector<std::pair<Die*, qint64>> m_validDice;
+ bool m_allTrue= false;
+
+ /*friend bool operator>(const ValidatorResult& a, const ValidatorResult& b)
+ {
+ if(a.m_validDice.size() > b.m_validDice.size())
+ return true;
+ if(a.m_validDice.size() == b.m_validDice.size())
+ {
+ if(!a.m_allTrue && b.m_allTrue)
+ return true;
+ else
+ return false;
+ }
+ return false;
+ }*/
+};
+/**
+ * @brief The BooleanCondition class is a Validator class checking validity from logic expression.
+ * It manages many operators (see : @ref LogicOperator).
+ */
+class ValidatorList
+{
+public:
+ ValidatorList();
+ virtual ~ValidatorList();
+
+ virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const;
+
+ void setOperationList(const QVector<Dice::LogicOperation>& m);
+ void setValidators(const QList<Validator*>& valids);
+
+ QString toString();
+
+ virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const;
+
+ virtual ValidatorList* getCopy() const;
+
+ void validResult(Result* result, bool recursive, bool unlight, std::function<void(Die*, qint64)> functor) const;
+
+private:
+ QVector<Dice::LogicOperation> m_operators;
+ QList<Validator*> m_validatorList;
+};
+
+#endif // VALIDATORLIST_H