diff options
| author | 2020-01-30 01:27:15 +0100 | |
|---|---|---|
| committer | 2020-03-28 02:05:05 +0100 | |
| commit | 653ba9395a36cc20ec1d68c9a9cae78973fa334c (patch) | |
| tree | 72753ed3bdca117baf001cdf8251b1fb22276eeb | |
| parent | 22d71d0032e2f44a8f267895aea3bd87864791b3 (diff) | |
| download | OneRoll-653ba9395a36cc20ec1d68c9a9cae78973fa334c.tar.gz OneRoll-653ba9395a36cc20ec1d68c9a9cae78973fa334c.zip | |
add unicity and repeat function part2
32 files changed, 2245 insertions, 1690 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 319e510..d1b0f93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ SET( dice_sources ${CMAKE_CURRENT_SOURCE_DIR}/range.cpp ${CMAKE_CURRENT_SOURCE_DIR}/booleancondition.cpp ${CMAKE_CURRENT_SOURCE_DIR}/validator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/compositevalidator.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 @@ -52,6 +52,7 @@ SET( dice_sources ${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 ) IF(STATIC_BUILD) diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 7fe65a4..6828d09 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,56 +1,11 @@ cmake_minimum_required(VERSION 3.5) option(UPDATE_TRANSLATIONS "update Translation" OFF) +option(NO_PAINTER_OPERATOR "No PAINTING" OFF) MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}") project(dice) -SET( dice_sources - ../diceparser.cpp - ../range.cpp - ../booleancondition.cpp - ../validator.cpp - ../compositevalidator.cpp - ../operationcondition.cpp - ../die.cpp - ../parsingtoolbox.cpp - ../dicealias.cpp - ../result/result.cpp - ../result/scalarresult.cpp - ../result/stringresult.cpp - ../result/diceresult.cpp - ../node/countexecutenode.cpp - ../node/dicerollernode.cpp - ../node/executionnode.cpp - ../node/explodedicenode.cpp - ../node/helpnode.cpp - ../node/mergenode.cpp - ../node/jumpbackwardnode.cpp - ../node/keepdiceexecnode.cpp - ../node/listaliasnode.cpp - ../node/allsamenode.cpp - ../node/listsetrollnode.cpp - ../node/numbernode.cpp - ../node/parenthesesnode.cpp - # ../ node/forloopnode.cpp - ../node/paintnode.cpp - ../node/rerolldicenode.cpp - ../node/scalaroperatornode.cpp - ../node/sortresult.cpp - ../node/startingnode.cpp - ../node/filternode.cpp - ../node/stringnode.cpp - ../node/ifnode.cpp - ../node/splitnode.cpp - ../node/groupnode.cpp - ../node/bind.cpp - ../node/occurencecountnode.cpp - ../node/uniquenode.cpp - ../highlightdice.cpp - ../node/variablenode.cpp - ../node/valueslistnode.cpp -) - # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. @@ -58,23 +13,23 @@ set(CMAKE_AUTOMOC ON) set(EXECUTABLE_OUTPUT_PATH bin/) # Find the QtWidgets library -find_package(Qt5Core) -include_directories(${Qt5Core_INCLUDES} ../) -add_definitions(${Qt5Core_DEFINITIONS}) +set(QT_REQUIRED_VERSION "5.12.0") + + -IF(NOT DEFINED NO_PAINTER_OPERATOR) +IF(NO_PAINTER_OPERATOR) + find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Svg LinguistTools) +else() MESSAGE(STATUS "Compilation of operator Paint") - find_package(Qt5Gui) - include_directories(${Qt5Gui_INCLUDES} ../) - add_definitions(${Qt5Gui_DEFINITIONS}) + find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Svg LinguistTools) add_definitions(-DPAINTER_OP) endif() + set(MODE "cli") ADD_DEFINITIONS( - -std=c++11 # Or -std=c++0x - # Other flags + -std=c++11 ) set(dice_RESOURCES diceparser.qrc) @@ -106,9 +61,12 @@ SET( cli_sources set(documentation_files ../HelpMe.md ../README.md) -add_executable( dice ${cli_sources} ${dice_QM} ${dice_sources} ${documentation_files}) -target_include_directories(dice PRIVATE ../include) - - -target_link_libraries(dice ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Svg_LIBRARIES}) +add_executable( dice ${cli_sources} ${dice_QM} ${documentation_files}) +set(diceparser_shared_INCLUDE_DIRS "../diceparser") +target_include_directories(dice PRIVATE ../include ../ ../result ../node) +IF(NO_PAINTER_OPERATOR) + target_link_libraries(dice PUBLIC Qt5::Core Qt5::Svg PRIVATE diceparser_shared) +ELSE() + target_link_libraries(dice PUBLIC Qt5::Core Qt5::Gui Qt5::Svg PRIVATE diceparser_shared) +ENDIF() INSTALL_TARGETS(/bin dice) diff --git a/cli/main.cpp b/cli/main.cpp index e09a1de..0008cba 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -443,7 +443,6 @@ int startDiceParsing(QStringList& cmds, QString& treeFile, bool withColor, EXPOR rt= 1; } } - parser.cleanAll(); return rt; } #include <QTextCodec> diff --git a/diceparser.cpp b/diceparser.cpp index acce867..e78700b 100644 --- a/diceparser.cpp +++ b/diceparser.cpp @@ -26,364 +26,63 @@ #include <QStringList> #include <functional> -#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/rerolldicenode.h" -#include "node/scalaroperatornode.h" -#include "node/sortresult.h" -#include "node/splitnode.h" -#include "node/startingnode.h" -#include "node/uniquenode.h" -#include "node/valueslistnode.h" -#include "node/variablenode.h" - #include "booleancondition.h" +#include "dicealias.h" #include "parsingtoolbox.h" #include "range.h" +#include "result/stringresult.h" #include "validator.h" #define DEFAULT_FACES_NUMBER 10 -DiceParser::DiceParser() -//: //m_start(nullptr),m_current(nullptr) -{ - m_currentTreeHasSeparator= false; - m_parsingToolbox= new ParsingToolBox(); - ParsingToolBox::setStartNodes(&m_startNodes); - - m_mapDiceOp= new QMap<QString, DiceOperator>(); - m_mapDiceOp->insert(QStringLiteral("D"), D); - m_mapDiceOp->insert(QStringLiteral("L"), L); - - m_OptionOp= new QMap<QString, OptionOperator>(); - 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); +DiceParser::DiceParser() : m_parsingToolbox(new ParsingToolBox()) {} +DiceParser::~DiceParser() {} - m_aliasList= new QList<DiceAlias*>(); - - m_nodeActionMap= new QMap<QString, NodeAction>(); - m_nodeActionMap->insert(QStringLiteral("@"), JumpBackward); - - m_commandList= new QStringList(); - m_commandList->append(QStringLiteral("help")); - m_commandList->append(QStringLiteral("la")); -} -DiceParser::~DiceParser() +const QList<DiceAlias*>& DiceParser::getAliases() const { - if(nullptr != m_commandList) - { - delete m_commandList; - m_commandList= nullptr; - } - if(nullptr != m_nodeActionMap) - { - delete m_nodeActionMap; - m_nodeActionMap= nullptr; - } - if(nullptr != m_OptionOp) - { - delete m_OptionOp; - m_OptionOp= nullptr; - } - if(nullptr != m_mapDiceOp) - { - delete m_mapDiceOp; - m_mapDiceOp= nullptr; - } - if(nullptr != m_parsingToolbox) - { - delete m_parsingToolbox; - m_parsingToolbox= nullptr; - } - if(nullptr != m_aliasList) - { - delete m_aliasList; - m_aliasList= nullptr; - } - if(nullptr != m_start) - { - delete m_start; - m_start= nullptr; - } -} - -QString DiceParser::convertAlias(QString str) -{ - for(auto& cmd : *m_aliasList) - { - if(cmd->isEnable()) - { - cmd->resolved(str); - } - } - return str; -} -QList<DiceAlias*>* DiceParser::getAliases() -{ - return m_aliasList; + return m_parsingToolbox->getAliases(); } void DiceParser::insertAlias(DiceAlias* dice, int i) { - if(i >= m_aliasList->size()) - { - m_aliasList->insert(i, dice); - } + m_parsingToolbox->insertAlias(dice, i); } bool DiceParser::parseLine(QString str, bool allowAlias) { - m_errorMap.clear(); - m_comment= QString(""); - cleanAll(); - m_currentTreeHasSeparator= false; if(allowAlias) { - str= convertAlias(str); + str= m_parsingToolbox->convertAlias(str); } m_command= str; - bool hasInstruction= readInstructionList(str); - bool value= hasInstruction; - if(!hasInstruction) + auto instructions= m_parsingToolbox->readInstructionList(str, true); + m_command.remove(m_parsingToolbox->getComment()); + bool value= !instructions.empty(); + if(!value) { - m_errorMap.insert( + 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(hasInstruction && !str.isEmpty()) + else if(value && !str.isEmpty()) { auto i= m_command.size() - str.size(); - m_warningMap.insert( + 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_errorMap.isEmpty()) + + if(m_parsingToolbox->hasError()) value= false; return value; } -bool DiceParser::readExpression(QString& str, ExecutionNode*& node) -{ - ExecutionNode* operandNode= nullptr; - if(m_parsingToolbox->readOpenParentheses(str)) - { - ExecutionNode* internalNode= nullptr; - if(readExpression(str, internalNode)) - { - ParenthesesNode* parentheseNode= new ParenthesesNode(); - parentheseNode->setInternelNode(internalNode); - node= parentheseNode; - if(m_parsingToolbox->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(readOptionFromNull(str, operandNode)) - { - node= operandNode; - return true; - } - else if(readOperatorFromNull(str, operandNode)) - { - node= operandNode; - return true; - } - else if(m_parsingToolbox->readOperand(str, operandNode)) - { - ExecutionNode* diceNode= nullptr; - if(readDice(str, diceNode)) - { - operandNode->setNextNode(diceNode); - } - node= operandNode; - - operandNode= ParsingToolBox::getLatestNode(operandNode); - // ExecutionNode* operatorNode=nullptr; - while(readOperator(str, operandNode)) - { - // operandNode->setNextNode(operatorNode); - operandNode= ParsingToolBox::getLatestNode(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 DiceParser::readOptionFromNull(QString& str, ExecutionNode*& node) -{ - StartingNode nodePrevious; - if(readOption(str, &nodePrevious)) - { - auto nodeNext= nodePrevious.getNextNode(); - nodePrevious.setNextNode(nullptr); - node= nodeNext; - return true; - } - return false; -} - -bool DiceParser::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 DiceParser::readValuesList(QString& str, ExecutionNode*& node) -{ - if(str.startsWith("[")) - { - str= str.remove(0, 1); - int pos= ParsingToolBox::findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]"); - if(-1 != pos) - { - QString liststr= str.left(pos); - auto list= liststr.split(","); - str= str.remove(0, pos + 1); - auto values= new ValuesListNode(); - for(auto var : list) - { - qint64 number= 1; - QString error; - 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; - } - } - return false; -} - -bool DiceParser::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; -} - -void DiceParser::cleanAll() -{ - if(!m_startNodes.empty()) - { - qDeleteAll(m_startNodes); - m_startNodes.clear(); - } -} - void DiceParser::start() { - for(auto start : m_startNodes) + for(auto start : m_parsingToolbox->getStartNodes()) { start->run(); } @@ -393,9 +92,9 @@ QList<qreal> DiceParser::getLastIntegerResults() { QList<qreal> resultValues; QStringList alreadyVisitedNode; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); Result* result= next->getResult(); bool scalarDone= false; while((result != nullptr) && (!scalarDone)) @@ -417,9 +116,9 @@ QList<qreal> DiceParser::getLastIntegerResults() QStringList DiceParser::getStringResult() { QStringList stringListResult; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); QString str; Result* result= next->getResult(); bool found= false; @@ -441,9 +140,9 @@ QStringList DiceParser::getAllStringResult(bool& hasAlias) { // QStringList allResult; QStringList stringListResult; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); Result* result= next->getResult(); while(nullptr != result) @@ -465,9 +164,9 @@ QStringList DiceParser::getAllStringResult(bool& hasAlias) QStringList DiceParser::getAllDiceResult(bool& hasAlias) { QStringList stringListResult; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); Result* result= next->getResult(); QList<Die*> dieListResult; @@ -508,9 +207,9 @@ QStringList DiceParser::getAllDiceResult(bool& hasAlias) void DiceParser::getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resultList) { - for(auto start : m_startNodes) + for(auto start : m_parsingToolbox->getStartNodes()) { - ExecutionNode* next= getLeafNode(start); + ExecutionNode* next= ParsingToolBox::getLeafNode(start); Result* result= next->getResult(); ExportedDiceResult nodeResult; while(nullptr != result) @@ -518,21 +217,18 @@ void DiceParser::getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resu if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) { DiceResult* diceResult= dynamic_cast<DiceResult*>(result); - if(diceResult) - { - QList<HighLightDice> list; - quint64 faces= 0; + QList<HighLightDice> list; + quint64 faces= 0; - for(auto& die : diceResult->getResultList()) - { - faces= die->getFaces(); - // qDebug() << "face" << faces; - HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(), - die->hasBeenDisplayed(), die->getFaces()); - list.append(hlDice); - } - nodeResult.insert(faces, list); + for(auto& die : diceResult->getResultList()) + { + faces= die->getFaces(); + // qDebug() << "face" << faces; + HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(), + die->hasBeenDisplayed(), die->getFaces()); + list.append(hlDice); } + nodeResult.insert(faces, list); } result= result->getPrevious(); } @@ -544,10 +240,10 @@ void DiceParser::getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resu void DiceParser::getLastDiceResult(QList<ExportedDiceResult>& diceValuesList, bool& homogeneous) { QSet<QString> alreadySeenDice; - for(auto start : m_startNodes) + for(auto start : m_parsingToolbox->getStartNodes()) { ExportedDiceResult diceValues; - ExecutionNode* next= getLeafNode(start); + ExecutionNode* next= ParsingToolBox::getLeafNode(start); Result* result= next->getResult(); while(nullptr != result) { @@ -614,7 +310,7 @@ QString DiceParser::getDiceCommand() const bool DiceParser::hasIntegerResultNotInFirst() { bool result= false; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { result|= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node); } @@ -624,7 +320,7 @@ bool DiceParser::hasIntegerResultNotInFirst() bool DiceParser::hasDiceResult() { bool result= false; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { result|= hasResultOfType(Dice::RESULT_TYPE::DICE_LIST, node); } @@ -633,7 +329,7 @@ bool DiceParser::hasDiceResult() bool DiceParser::hasStringResult() { bool result= false; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { result|= hasResultOfType(Dice::RESULT_TYPE::STRING, node); } @@ -642,7 +338,7 @@ bool DiceParser::hasStringResult() bool DiceParser::hasResultOfType(Dice::RESULT_TYPE type, ExecutionNode* node, bool notthelast) { bool scalarDone= false; - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); Result* result= next->getResult(); while((result != nullptr) && (!scalarDone)) { @@ -661,10 +357,10 @@ bool DiceParser::hasResultOfType(Dice::RESULT_TYPE type, ExecutionNode* node, bo QList<qreal> DiceParser::getSumOfDiceResult() { QList<qreal> resultValues; - for(auto node : m_startNodes) + for(auto node : m_parsingToolbox->getStartNodes()) { qreal resultValue= 0; - ExecutionNode* next= getLeafNode(node); + ExecutionNode* next= ParsingToolBox::getLeafNode(node); Result* result= next->getResult(); bool found= false; while((nullptr != result) && (!found)) @@ -689,714 +385,24 @@ QList<qreal> DiceParser::getSumOfDiceResult() } int DiceParser::getStartNodeCount() const { - return static_cast<int>(m_startNodes.size()); -} -ExecutionNode* DiceParser::getLeafNode(ExecutionNode* start) -{ - ExecutionNode* next= start; - while(nullptr != next->getNextNode()) - { - next= next->getNextNode(); - } - return next; -} - -bool DiceParser::readDice(QString& str, ExecutionNode*& node) -{ - DiceOperator currentOperator; - - if(readDiceOperator(str, currentOperator)) - { - if(currentOperator == D) - { - qint64 max; - qint64 min; - bool unique= (ParsingToolBox::UNIQUE == m_parsingToolbox->readListOperator(str)) ? true : false; - Die::ArithmeticOperator op; - - bool hasOp= m_parsingToolbox->readArithmeticOperator(str, op); - if(m_parsingToolbox->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::getLatestNode(current); - } - return true; - } - else if(m_parsingToolbox->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::getLatestNode(current); - } - return true; - } - } - else if(currentOperator == L) - { - QStringList list; - QList<Range> listRange; - ParsingToolBox::LIST_OPERATOR op= m_parsingToolbox->readListOperator(str); - if(m_parsingToolbox->readList(str, list, listRange)) - { - ListSetRollNode* lsrNode= new ListSetRollNode(); - lsrNode->setRangeList(listRange); - if(op == ParsingToolBox::UNIQUE) - { - lsrNode->setUnique(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 DiceParser::readDiceOperator(QString& str, DiceOperator& op) -{ - QStringList listKey= m_mapDiceOp->keys(); - for(const QString& key : listKey) - { - if(str.startsWith(key, Qt::CaseInsensitive)) - { - str= str.remove(0, key.size()); - op= m_mapDiceOp->value(key); - return true; - } - } - return false; -} -bool DiceParser::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 DiceParser::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 DiceParser::readInstructionOperator(QChar c) -{ - if(c == ';') - { - return true; - } - return false; -} -bool DiceParser::readInstructionList(QString& str) -{ - if(str.isEmpty()) - return false; - - bool hasInstruction= false; - bool readInstruction= true; - while(readInstruction) - { - ExecutionNode* startNode= nullptr; - bool keepParsing= readExpression(str, startNode); - if(nullptr != startNode) - { - hasInstruction= true; - m_startNodes.push_back(startNode); - auto latest= startNode; - if(keepParsing) - { - latest= ParsingToolBox::getLatestNode(latest); - keepParsing= !str.isEmpty(); - while(keepParsing) - { - auto before= str; - if(readOperator(str, latest)) - { - latest= ParsingToolBox::getLatestNode(latest); - } - keepParsing= (!str.isEmpty() && (before != str)); - } - } - if(!str.isEmpty() && readInstructionOperator(str[0])) - { - str= str.remove(0, 1); - } - else - { - QString result; - QString comment; - if(m_parsingToolbox->readComment(str, result, comment)) - { - m_command.remove(comment); - m_comment= result; - } - readInstruction= false; - } - } - else - { - readInstruction= false; - } - } - return hasInstruction; -} - -bool DiceParser::readOperator(QString& str, ExecutionNode* previous) -{ - if(str.isEmpty() || nullptr == previous) - { - return false; - } - - Die::ArithmeticOperator op; - if(m_parsingToolbox->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 false; - } - 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); - - return true; - } - else - { - delete node; - } - } - else - { - while(readOption(str, previous)) - { - previous= ParsingToolBox::getLatestNode(previous); - } - } - return false; -} -bool DiceParser::hasSeparator() const -{ - return m_currentTreeHasSeparator; -} -DiceRollerNode* DiceParser::addRollDiceNode(qint64 faces, ExecutionNode* previous) -{ - DiceRollerNode* mydiceRoller= new DiceRollerNode(faces); - previous->setNextNode(mydiceRoller); - return mydiceRoller; -} -ExplodeDiceNode* DiceParser::addExplodeDiceNode(qint64 value, ExecutionNode* previous) -{ - ExplodeDiceNode* explodeDiceNode= new ExplodeDiceNode(); - NumberNode* node= new NumberNode(); - node->setNumber(value); - BooleanCondition* condition= new BooleanCondition(); - condition->setValueNode(node); - condition->setOperator(BooleanCondition::Equal); - m_parsingToolbox->isValidValidator(previous, condition); - explodeDiceNode->setValidator(condition); - previous->setNextNode(explodeDiceNode); - return explodeDiceNode; -} -bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, -{ - if(str.isEmpty()) - { - return false; - } - - ExecutionNode* node= nullptr; - 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: - { - qint64 myNumber= 0; - bool ascending= m_parsingToolbox->readAscending(str); - - if(m_parsingToolbox->readNumber(str, myNumber)) - { - node= m_parsingToolbox->addSort(previous, ascending); - KeepDiceExecNode* nodeK= new KeepDiceExecNode(); - nodeK->setDiceKeepNumber(myNumber); - node->setNextNode(nodeK); - node= nodeK; - found= true; - } - } - break; - case KeepAndExplode: - { - qint64 myNumber= 0; - bool ascending= m_parsingToolbox->readAscending(str); - if(m_parsingToolbox->readNumber(str, myNumber)) - { - /* if(!hasDice) - { - previous = addRollDiceNode(DEFAULT_FACES_NUMBER,previous); - }*/ - DiceRollerNode* nodeTmp= dynamic_cast<DiceRollerNode*>(previous); - if(nullptr != nodeTmp) - { - previous= addExplodeDiceNode(static_cast<qint64>(nodeTmp->getFaces()), previous); - } - - node= m_parsingToolbox->addSort(previous, ascending); - - KeepDiceExecNode* nodeK= new KeepDiceExecNode(); - nodeK->setDiceKeepNumber(myNumber); - - node->setNextNode(nodeK); - node= nodeK; - found= true; - } - } - break; - case Filter: - { - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - if(nullptr != validator) - { - m_parsingToolbox->isValidValidator(previous, validator); - - FilterNode* filterNode= new FilterNode(); - filterNode->setValidator(validator); - - previous->setNextNode(filterNode); - node= filterNode; - found= true; - } - } - break; - case Sort: - { - bool ascending= m_parsingToolbox->readAscending(str); - node= m_parsingToolbox->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: - { - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - if(nullptr != validator) - { - m_parsingToolbox->isValidValidator(previous, validator); - - CountExecuteNode* countNode= new CountExecuteNode(); - countNode->setValidator(validator); - - previous->setNextNode(countNode); - node= 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 - { - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - QString symbol= m_OptionOp->key(operatorName); - if(nullptr != validator) - { - switch(m_parsingToolbox->isValidValidator(previous, validator)) - { - 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->setValidator(validator); - previous->setNextNode(rerollNode); - node= 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: - { - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - if(nullptr != validator) - { - if(Dice::CONDITION_STATE::ALWAYSTRUE == m_parsingToolbox->isValidValidator(previous, validator)) - { - m_errorMap.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR, - QObject::tr("This condition %1 introduces an endless loop. Please, change it") - .arg(validator->toString())); - } - ExplodeDiceNode* explodedNode= new ExplodeDiceNode(); - explodedNode->setValidator(validator); - previous->setNextNode(explodedNode); - node= 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); - node= mergeNode; - found= true; - } - break; - case AllSameExplode: - { - AllSameNode* allSame= new AllSameNode(); - previous->setNextNode(allSame); - node= allSame; - found= true; - } - break; - case Bind: - { - BindNode* bindNode= new BindNode(); - bindNode->setStartList(&m_startNodes); - previous->setNextNode(bindNode); - node= bindNode; - found= true; - } - break; - case Occurences: - { - qint64 number= 0; - auto occNode= new OccurenceCountNode(); - if(m_parsingToolbox->readNumber(str, number)) - { - occNode->setWidth(number); - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - if(validator) - { - occNode->setValidator(validator); - } - else if(m_parsingToolbox->readComma(str)) - { - if(m_parsingToolbox->readNumber(str, number)) - { - occNode->setHeight(number); - } - } - } - previous->setNextNode(occNode); - node= occNode; - found= true; - } - break; - case Unique: - { - node= new UniqueNode(); - previous->setNextNode(node); - found= true; - } - break; - case Painter: - { - PainterNode* painter= new PainterNode(); - if(!m_parsingToolbox->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); - node= painter; - found= true; - } - } - break; - case ifOperator: - { - IfNode* nodeif= new IfNode(); - nodeif->setConditionType(m_parsingToolbox->readConditionType(str)); - Validator* validator= m_parsingToolbox->readCompositeValidator(str); - if(nullptr != validator) - { - ExecutionNode* trueNode= nullptr; - ExecutionNode* falseNode= nullptr; - if(readIfInstruction(str, trueNode, falseNode)) - { - nodeif->setInstructionTrue(trueNode); - nodeif->setInstructionFalse(falseNode); - nodeif->setValidator(validator); - previous->setNextNode(nodeif); - node= nodeif; - found= true; - } - else - { - delete nodeif; - } - } - else - { - delete nodeif; - } - break; - } - case Split: - { - SplitNode* splitnode= new SplitNode(); - previous->setNextNode(splitnode); - node= splitnode; - found= true; - } - break; - case Group: - { - qint64 groupNumber= 0; - if(m_parsingToolbox->readNumber(str, groupNumber)) - { - GroupNode* groupNode= new GroupNode(); - groupNode->setGroupValue(groupNumber); - previous->setNextNode(groupNode); - node= groupNode; - found= true; - } - } - break; - } - } - } - return found; -} -bool DiceParser::readIfInstruction(QString& str, ExecutionNode*& trueNode, ExecutionNode*& falseNode) -{ - if(readBlocInstruction(str, trueNode)) - { - if(readBlocInstruction(str, falseNode)) - { - return true; - } - return true; - } - return false; -} - -bool DiceParser::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 DiceParser::readBlocInstruction(QString& str, ExecutionNode*& resultnode) -{ - if(str.startsWith('{')) - { - str= str.remove(0, 1); - ExecutionNode* node= nullptr; - Die::ArithmeticOperator op; - ScalarOperatorNode* scalarNode= nullptr; - if(m_parsingToolbox->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; + return static_cast<int>(m_parsingToolbox->getStartNodes().size()); } QString DiceParser::getComment() const { - return m_comment; + return m_parsingToolbox->getComment(); } void DiceParser::setComment(const QString& comment) { - m_comment= comment; + m_parsingToolbox->setComment(comment); } QMap<Dice::ERROR_CODE, QString> DiceParser::getErrorMap() { QMap<Dice::ERROR_CODE, QString> map; - for(auto start : m_startNodes) + for(auto start : m_parsingToolbox->getStartNodes()) { auto mapTmp= start->getExecutionErrorMap(); auto keys= mapTmp.keys(); @@ -1409,7 +415,8 @@ QMap<Dice::ERROR_CODE, QString> DiceParser::getErrorMap() } QString DiceParser::humanReadableError() { - QMapIterator<Dice::ERROR_CODE, QString> i(m_errorMap); + auto errorMap= m_parsingToolbox->getErrorList(); + QMapIterator<Dice::ERROR_CODE, QString> i(errorMap); QString str(""); while(i.hasNext()) { @@ -1431,7 +438,8 @@ QString DiceParser::humanReadableError() QString DiceParser::humanReadableWarning() { - QMapIterator<Dice::ERROR_CODE, QString> i(m_warningMap); + auto warningMap= m_parsingToolbox->getWarningList(); + QMapIterator<Dice::ERROR_CODE, QString> i(warningMap); QString str(""); while(i.hasNext()) { @@ -1444,11 +452,11 @@ QString DiceParser::humanReadableWarning() void DiceParser::writeDownDotTree(QString filepath) { - if(m_startNodes.empty()) + if(m_parsingToolbox->getStartNodes().empty()) return; QString str(QStringLiteral("digraph ExecutionTree {\n")); - for(auto start : m_startNodes) + for(auto start : m_parsingToolbox->getStartNodes()) { start->generateDotTree(str); } @@ -1463,7 +471,7 @@ void DiceParser::writeDownDotTree(QString filepath) } void DiceParser::setPathToHelp(QString l) { - m_helpPath= l; + m_parsingToolbox->setHelpPath(l); } void DiceParser::setVariableDictionary(const QHash<QString, QString>& variables) { diff --git a/include/diceparser.h b/include/diceparser.h index 31f9760..e60f30d 100644 --- a/include/diceparser.h +++ b/include/diceparser.h @@ -24,6 +24,7 @@ #include <QMap> #include <QString> +#include <memory> #include <vector> #include "diceparserhelper.h" @@ -53,52 +54,6 @@ class DiceParser { public: /** - * @brief The DiceOperator enum gathering all dice operators - */ - enum DiceOperator - { - D, - L - }; - /** - * @brief The DiceSymbol enum - */ - enum NodeAction - { - JumpBackward - }; - /** - * @brief The OptionOperator enum gathering all options availables for result. - */ - enum OptionOperator - { - KeepAndExplode, - Keep, - Reroll, - RerollUntil, - Explode, - Sort, - Count, - RerollAndAdd, - Merge, - ifOperator, - Painter, - Filter, - Split, - Group, - Occurences, - Unique, - Bind, - AllSameExplode - }; - /** - * @brief The CommandOperator enum - */ - enum CommandOperator - { - }; - - /** * @brief DiceParser default constructor */ DiceParser(); @@ -178,18 +133,12 @@ public: * @brief getAliases * @return */ - QList<DiceAlias*>* getAliases(); + const QList<DiceAlias*>& getAliases() const; /** * @brief insertAlias */ void insertAlias(DiceAlias*, int); /** - * @brief DiceParser::convertAlias - * @param str - * @return - */ - QString convertAlias(QString str); - /** * @brief getErrorList * @return */ @@ -227,106 +176,10 @@ public: void getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resultList); QString humanReadableWarning(); - bool readValuesList(QString& str, ExecutionNode*& node); void cleanAll(); private: /** - * @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 readInstructionList(QString& str); - bool readOptionFromNull(QString& str, ExecutionNode*& node); - bool readOperatorFromNull(QString& str, ExecutionNode*& node); - bool readParameterNode(QString& str, ExecutionNode*& node); - /** - * @brief readExpression - * @param str - * @param node - * @return - */ - bool readExpression(QString& str, ExecutionNode*& node); - /** - * @brief readDice - * @param str - * @return - */ - bool readDice(QString& str, ExecutionNode*& node); - /** - * @brief readDiceOperator - * @return - */ - bool readDiceOperator(QString&, DiceOperator&); - /** - * @brief readDiceExpression - * @param node - * @return - */ - bool readDiceExpression(QString&, ExecutionNode*& node); - /** - * @brief readOperator - * @return - */ - bool readOperator(QString&, ExecutionNode* previous); - /** - * @brief DiceParser::readCommand - * @param str - * @param node - * @return - */ - bool readCommand(QString& str, ExecutionNode*& node); - - /** - * @brief readOption - */ - bool readOption(QString&, ExecutionNode* node); // OptionOperator& option, - - /** - * @brief addRollDiceNode - * @param faces - * @return - */ - DiceRollerNode* addRollDiceNode(qint64 faces, ExecutionNode*); - /** - * @brief addExplodeDiceNode - * @param faces - * @param previous - * @return - */ - ExplodeDiceNode* addExplodeDiceNode(qint64 faces, ExecutionNode* previous); - /** - * @brief readOperand - * @param node - * @return - */ - bool readOperand(QString&, ExecutionNode*& node); - - /** - * @brief readInstructionOperator - * @param c - * @return - */ - bool readInstructionOperator(QChar c); - /** - * @brief readNode - * @param str - * @param node - * @return - */ - bool readNode(QString& str, ExecutionNode*& node); - - /** - * @brief getLeafNode - * @return - */ - ExecutionNode* getLeafNode(ExecutionNode* node); - - /** * @brief hasResultOfType * @param notthelast * @return @@ -335,22 +188,8 @@ private: bool readBlocInstruction(QString& str, ExecutionNode*& resultnode); private: - QMap<QString, DiceOperator>* m_mapDiceOp; - QMap<QString, OptionOperator>* m_OptionOp; - QMap<QString, NodeAction>* m_nodeActionMap; - QList<DiceAlias*>* m_aliasList; - QStringList* m_commandList; - - QMap<Dice::ERROR_CODE, QString> m_errorMap; - QMap<Dice::ERROR_CODE, QString> m_warningMap; - - ExecutionNode* m_start= nullptr; - std::vector<ExecutionNode*> m_startNodes; + std::unique_ptr<ParsingToolBox> m_parsingToolbox; QString m_command; - ParsingToolBox* m_parsingToolbox; - QString m_helpPath; - bool m_currentTreeHasSeparator; - QString m_comment; }; #endif // DICEPARSER_H diff --git a/include/diceparserhelper.h b/include/diceparserhelper.h index 1b91285..461d127 100644 --- a/include/diceparserhelper.h +++ b/include/diceparserhelper.h @@ -39,5 +39,15 @@ enum class RESULT_TYPE : int STRING= 2, DICE_LIST= 4 }; -} +/** + * @brief The ConditionType enum defines compare method + */ +enum ConditionType +{ + OnEach, + OneOfThem, + AllOfThem, + OnScalar +}; +} // namespace Dice #endif // DICEPARSERHELPER_H diff --git a/include/parsingtoolbox.h b/include/parsingtoolbox.h index 038427f..701d2d3 100644 --- a/include/parsingtoolbox.h +++ b/include/parsingtoolbox.h @@ -23,9 +23,9 @@ #define PARSINGTOOLBOX_H #include <QMap> +#include <vector> #include "booleancondition.h" -#include "compositevalidator.h" #include "highlightdice.h" #include "node/dicerollernode.h" #include "node/executionnode.h" @@ -34,6 +34,11 @@ #include "node/scalaroperatornode.h" #include "operationcondition.h" #include "range.h" +#include "validatorlist.h" + +class RepeaterNode; +class DiceAlias; +class ExplodeDiceNode; class SubtituteInfo { @@ -73,7 +78,49 @@ public: NONE, UNIQUE }; - + enum Function + { + REPEAT + }; + /** + * @brief The OptionOperator enum gathering all options availables for result. + */ + enum OptionOperator + { + KeepAndExplode, + Keep, + Reroll, + RerollUntil, + Explode, + Sort, + Count, + RerollAndAdd, + Merge, + ifOperator, + Painter, + Filter, + Split, + Group, + Occurences, + Unique, + Bind, + AllSameExplode + }; + /** + * @brief The DiceOperator enum gathering all dice operators + */ + enum DiceOperator + { + D, + L + }; + /** + * @brief The DiceSymbol enum + */ + enum NodeAction + { + JumpBackward + }; /** * @brief ParsingToolBox */ @@ -87,6 +134,8 @@ public: * @brief ~ParsingToolBox */ virtual ~ParsingToolBox(); + + void clearUp(); /** * @brief addSort * @param e @@ -118,7 +167,7 @@ public: * @param str * @return */ - Validator* readCompositeValidator(QString& str); + ValidatorList* readValidatorList(QString& str); /** * @brief readNumber read number in the given str and remove from the string the read character. @@ -176,7 +225,7 @@ public: * @param val * @return */ - Dice::CONDITION_STATE isValidValidator(ExecutionNode* previous, Validator* val); + Dice::CONDITION_STATE isValidValidator(ExecutionNode* previous, ValidatorList* val); /** * @brief getDiceRollerNode * @param previous @@ -201,11 +250,12 @@ public: void readProbability(QStringList& str, QList<Range>& ranges); - bool readLogicOperation(QString& str, CompositeValidator::LogicOperation& op); + bool readLogicOperation(QString& str, ValidatorList::LogicOperation& op); bool readDiceLogicOperator(QString& str, OperationCondition::ConditionOperator& op); bool readArithmeticOperator(QString& str, Die::ArithmeticOperator& op); + std::vector<ExecutionNode*> readInstructionList(QString& str, bool startNode); static bool readPainterParameter(PainterNode* painter, QString& str); @@ -216,15 +266,15 @@ public: * @param str * @return */ - static IfNode::ConditionType readConditionType(QString& str); + static Dice::ConditionType readConditionType(QString& str); bool readComment(QString& str, QString&, QString&); static ExecutionNode* getLatestNode(ExecutionNode* node); - static std::vector<ExecutionNode*>* getStartNodes(); + const std::vector<ExecutionNode*>& getStartNodes(); static void setStartNodes(std::vector<ExecutionNode*>* startNodes); - static bool readOperand(QString& str, ExecutionNode*& node); + bool readOperand(QString& str, ExecutionNode*& node); static int findClosingCharacterIndexOf(QChar open, QChar closing, const QString& str, int offset); static QString replaceVariableToValue(const QString& source, QStringList values); @@ -237,14 +287,114 @@ public: static bool readComma(QString& str); + bool readReaperArguments(RepeaterNode* node, QString& source); + + DiceRollerNode* addRollDiceNode(qint64 faces, ExecutionNode*); + + ExplodeDiceNode* addExplodeDiceNode(qint64 faces, ExecutionNode* previous); + + bool readExpression(QString& str, ExecutionNode*& node); + + static ExecutionNode* getLeafNode(ExecutionNode* start); + + bool hasError() const; + + 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); + /** + * @brief readDice + * @param str + * @return + */ + bool readDice(QString& str, ExecutionNode*& node); + /** + * @brief readDiceOperator + * @return + */ + bool readDiceOperator(QString&, DiceOperator&); + /** + * @brief readDiceExpression + * @param node + * @return + */ + bool readDiceExpression(QString&, ExecutionNode*& node); + /** + * @brief readOperator + * @return + */ + bool readOperator(QString&, ExecutionNode* previous); + /** + * @brief DiceParser::readCommand + * @param str + * @param node + * @return + */ + bool readCommand(QString& str, ExecutionNode*& node); + + /** + * @brief readOption + */ + bool readOption(QString&, ExecutionNode* node); // OptionOperator& option, + + bool readValuesList(QString& str, ExecutionNode*& node); + + void addError(Dice::ERROR_CODE code, const QString& msg); + void addWarning(Dice::ERROR_CODE code, const QString& msg); + + void setComment(const QString& comment); + QString getComment() const; + + const QMap<Dice::ERROR_CODE, QString>& getErrorList() const; + const QMap<Dice::ERROR_CODE, QString>& getWarningList() const; + + QString convertAlias(QString str); + + bool readBlocInstruction(QString& str, ExecutionNode*& resultnode); + + void setHelpPath(const QString& path); + + void insertAlias(DiceAlias* dice, int i); + const QList<DiceAlias*>& getAliases() const; + private: - QMap<QString, BooleanCondition::LogicOperator>* m_logicOp; - QMap<QString, CompositeValidator::LogicOperation>* m_logicOperation; - QMap<QString, OperationCondition::ConditionOperator>* m_conditionOperation; - QHash<QString, Die::ArithmeticOperator>* m_arithmeticOperation; + QMap<QString, BooleanCondition::LogicOperator> m_logicOp; + QMap<QString, ValidatorList::LogicOperation> m_logicOperation; + QMap<QString, OperationCondition::ConditionOperator> m_conditionOperation; + QHash<QString, Die::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; - static std::vector<ExecutionNode*>* m_startNodes; + QString m_helpPath; + QList<DiceAlias*> m_aliasList; }; #endif // PARSINGTOOLBOX_H diff --git a/node/countexecutenode.cpp b/node/countexecutenode.cpp index c9b78b2..7d684c6 100644 --- a/node/countexecutenode.cpp +++ b/node/countexecutenode.cpp @@ -1,19 +1,20 @@ #include "countexecutenode.h" #include "result/diceresult.h" +#include "validatorlist.h" -CountExecuteNode::CountExecuteNode() : m_scalarResult(new ScalarResult()), m_validator(nullptr) +CountExecuteNode::CountExecuteNode() : m_scalarResult(new ScalarResult()), m_validatorList(nullptr) { m_result= m_scalarResult; } -void CountExecuteNode::setValidator(Validator* validator) +void CountExecuteNode::setValidatorList(ValidatorList* validatorlist) { - m_validator= validator; + m_validatorList= validatorlist; } CountExecuteNode::~CountExecuteNode() { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - delete m_validator; + delete m_validatorList; } } @@ -28,17 +29,10 @@ void CountExecuteNode::run(ExecutionNode* previous) if(nullptr != previousResult) { m_result->setPrevious(previousResult); - QList<Die*> diceList= previousResult->getResultList(); qint64 sum= 0; - for(Die* dice : diceList) - { - if(nullptr != m_validator) - { - sum+= m_validator->hasValid(dice, true, true); - } - } + 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); @@ -49,7 +43,7 @@ QString CountExecuteNode::toString(bool withlabel) const { if(withlabel) { - return QString("%1 [label=\"CountExecuteNode %2\"]").arg(m_id, m_validator->toString()); + return QString("%1 [label=\"CountExecuteNode %2\"]").arg(m_id, m_validatorList->toString()); } else { @@ -69,9 +63,9 @@ qint64 CountExecuteNode::getPriority() const ExecutionNode* CountExecuteNode::getCopy() const { CountExecuteNode* node= new CountExecuteNode(); - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - node->setValidator(m_validator->getCopy()); + node->setValidatorList(m_validatorList->getCopy()); } if(nullptr != m_nextNode) { diff --git a/node/countexecutenode.h b/node/countexecutenode.h index 8969a41..37b7a4f 100644 --- a/node/countexecutenode.h +++ b/node/countexecutenode.h @@ -4,8 +4,8 @@ #include "executionnode.h" #include "result/scalarresult.h" -#include "validator.h" +class ValidatorList; /** * @brief The CountExecuteNode class */ @@ -25,7 +25,7 @@ public: /** * @brief setValidator */ - virtual void setValidator(Validator*); + virtual void setValidatorList(ValidatorList*); /** * @brief toString * @return @@ -44,7 +44,7 @@ public: private: ScalarResult* m_scalarResult; - Validator* m_validator; + ValidatorList* m_validatorList; }; #endif // COUNTEXECUTENODE_H diff --git a/node/explodedicenode.cpp b/node/explodedicenode.cpp index 2292a05..1546883 100644 --- a/node/explodedicenode.cpp +++ b/node/explodedicenode.cpp @@ -1,6 +1,7 @@ #include "explodedicenode.h" +#include "validatorlist.h" -ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult()), m_validator(nullptr) +ExplodeDiceNode::ExplodeDiceNode() : m_diceResult(new DiceResult()) { m_result= m_diceResult; } @@ -13,19 +14,22 @@ void ExplodeDiceNode::run(ExecutionNode* previous) 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(); + // QList<Die*> list= m_diceResult->getResultList(); - for(auto& die : list) - { + bool hasExploded= false; + std::function<void(Die*, qint64)> f= [&hasExploded, this](Die* die, qint64) { if(Dice::CONDITION_STATE::ALWAYSTRUE - == m_validator->isValidRangeSize(std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue()))) + == 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") @@ -33,14 +37,31 @@ void ExplodeDiceNode::run(ExecutionNode* previous) .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_validator->hasValid(die, false)) + while(m_validatorList->hasValid(die, false)) { die->roll(true); } - } + }*/ if(nullptr != m_nextNode) { @@ -51,20 +72,20 @@ void ExplodeDiceNode::run(ExecutionNode* previous) } ExplodeDiceNode::~ExplodeDiceNode() { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - delete m_validator; + delete m_validatorList; } } -void ExplodeDiceNode::setValidator(Validator* val) +void ExplodeDiceNode::setValidatorList(ValidatorList* val) { - m_validator= val; + m_validatorList= val; } QString ExplodeDiceNode::toString(bool withlabel) const { if(withlabel) { - return QString("%1 [label=\"ExplodeDiceNode %2\"]").arg(m_id, m_validator->toString()); + return QString("%1 [label=\"ExplodeDiceNode %2\"]").arg(m_id, m_validatorList->toString()); } else { @@ -84,9 +105,9 @@ qint64 ExplodeDiceNode::getPriority() const ExecutionNode* ExplodeDiceNode::getCopy() const { ExplodeDiceNode* node= new ExplodeDiceNode(); - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - node->setValidator(m_validator->getCopy()); + node->setValidatorList(m_validatorList->getCopy()); } if(nullptr != m_nextNode) { diff --git a/node/explodedicenode.h b/node/explodedicenode.h index e72298a..77b4a44 100644 --- a/node/explodedicenode.h +++ b/node/explodedicenode.h @@ -3,8 +3,8 @@ #include "executionnode.h" #include "result/diceresult.h" -#include "validator.h" -#include <QDebug> + +class ValidatorList; /** * @brief The ExplodeDiceNode class explode dice while is valid by the validator. @@ -15,7 +15,7 @@ public: ExplodeDiceNode(); virtual ~ExplodeDiceNode(); virtual void run(ExecutionNode* previous= nullptr); - virtual void setValidator(Validator*); + virtual void setValidatorList(ValidatorList*); virtual QString toString(bool) const; virtual qint64 getPriority() const; @@ -23,7 +23,7 @@ public: protected: DiceResult* m_diceResult; - Validator* m_validator; + ValidatorList* m_validatorList= nullptr; }; #endif // EXPLOSEDICENODE_H diff --git a/node/filternode.cpp b/node/filternode.cpp index d5d155a..4424b4b 100644 --- a/node/filternode.cpp +++ b/node/filternode.cpp @@ -1,4 +1,5 @@ #include "filternode.h" +#include "validatorlist.h" FilterNode::FilterNode() : m_diceResult(new DiceResult()), m_eachValue(false) { @@ -7,14 +8,14 @@ FilterNode::FilterNode() : m_diceResult(new DiceResult()), m_eachValue(false) FilterNode::~FilterNode() { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - delete m_validator; + delete m_validatorList; } } -void FilterNode::setValidator(Validator* validator) +void FilterNode::setValidatorList(ValidatorList* validatorlist) { - m_validator= validator; + m_validatorList= validatorlist; } void FilterNode::run(ExecutionNode* previous) { @@ -25,24 +26,27 @@ void FilterNode::run(ExecutionNode* previous) } DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previous->getResult()); m_result->setPrevious(previousDiceResult); + if(nullptr != previousDiceResult) { - QList<Die*> diceList= previousDiceResult->getResultList(); 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) { - if(m_validator->hasValid(tmp, m_eachValue)) - { - Die* tmpdie= new Die(*tmp); - //*tmpdie= *tmp; - diceList2.append(tmpdie); - tmp->displayed(); - } - else - { - tmp->setHighlighted(false); - } + tmp->setHighlighted(false); } m_diceResult->setResultList(diceList2); @@ -77,9 +81,9 @@ qint64 FilterNode::getPriority() const ExecutionNode* FilterNode::getCopy() const { FilterNode* node= new FilterNode(); - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - node->setValidator(m_validator->getCopy()); + node->setValidatorList(m_validatorList->getCopy()); } if(nullptr != m_nextNode) { diff --git a/node/filternode.h b/node/filternode.h index 77ae7b6..7af6fe2 100644 --- a/node/filternode.h +++ b/node/filternode.h @@ -4,7 +4,8 @@ #include "executionnode.h" #include "result/diceresult.h" -#include "validator.h" + +class ValidatorList; class FilterNode : public ExecutionNode { @@ -16,7 +17,7 @@ public: /** * @brief setValidator */ - virtual void setValidator(Validator*); + virtual void setValidatorList(ValidatorList*); /** * @brief toString * @return @@ -32,7 +33,7 @@ public: private: DiceResult* m_diceResult; - Validator* m_validator; + ValidatorList* m_validatorList; bool m_eachValue; }; diff --git a/node/ifnode.cpp b/node/ifnode.cpp index 5fa68b0..b2f183c 100644 --- a/node/ifnode.cpp +++ b/node/ifnode.cpp @@ -19,7 +19,7 @@ ***************************************************************************/ #include "ifnode.h" #include "result/diceresult.h" -#include "result/stringresult.h" +#include "validatorlist.h" PartialDiceRollNode::PartialDiceRollNode() : m_diceResult(new DiceResult) { @@ -80,9 +80,8 @@ DiceResult* getFirstDiceResult(Result* result) return found; } -// -IfNode::IfNode() : m_validator(nullptr), m_conditionType(AllOfThem), m_true(nullptr), m_false(nullptr) +IfNode::IfNode() : m_conditionType(Dice::AllOfThem), m_true(nullptr), m_false(nullptr) { // m_result = new DiceResult(); } @@ -109,24 +108,20 @@ void IfNode::run(ExecutionNode* previous) { qreal value= previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(); - if(nullptr != m_validator) + if(nullptr != m_validatorList) { DiceResult* previousDiceResult= getFirstDiceResult(previousResult); if(nullptr != previousDiceResult) { QList<Die*> diceList= previousDiceResult->getResultList(); - if(m_conditionType == OnEach) + if(m_conditionType == Dice::OnEach) { - auto resultOnEach= m_result; for(Die* dice : diceList) { - auto diceResult= new DiceResult; - StringResult* stringResult= nullptr; auto diceNode= new PartialDiceRollNode(); - auto cpyDice= new Die(*dice); - diceNode->insertDie(cpyDice); - if(m_validator->hasValid(dice, true, true)) + diceNode->insertDie(new Die(*dice)); + if(m_validatorList->hasValid(dice, true, true)) { nextNode= (nullptr == m_true) ? nullptr : m_true->getCopy(); } @@ -141,49 +136,17 @@ void IfNode::run(ExecutionNode* previous) { previousLoop->setNextNode(nextNode); } + if(nullptr == m_nextNode) + { + m_nextNode= nextNode; + } diceNode->setNextNode(nextNode); diceNode->run(previousLoop); previousLoop= getLeafNode(nextNode); } - - if(nullptr == nextNode) - { - diceResult->insertResult(cpyDice); - } - else - { - delete cpyDice; - auto branchResult= previousLoop->getResult(); - if(branchResult->hasResultOfType(Dice::RESULT_TYPE::SCALAR)) - { - auto val= branchResult->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); - auto valDie= new Die(); - valDie->insertRollValue(val); - diceResult->insertResult(valDie); - } - else if(branchResult->hasResultOfType(Dice::RESULT_TYPE::STRING)) - { - auto val= branchResult->getResult(Dice::RESULT_TYPE::STRING).toString(); - stringResult= new StringResult; - stringResult->setText(val); - } - } - if(nullptr != stringResult) - { - stringResult->setPrevious(resultOnEach); - resultOnEach= stringResult; - delete diceResult; - } - else - { - diceResult->setPrevious(resultOnEach); - resultOnEach= diceResult; - } } - - m_result= resultOnEach; } - else if((m_conditionType == OneOfThem) || (m_conditionType == AllOfThem)) + else if((m_conditionType == Dice::OneOfThem) || (m_conditionType == Dice::AllOfThem)) { bool trueForAll= true; bool falseForAll= true; @@ -193,14 +156,14 @@ void IfNode::run(ExecutionNode* previous) for(Die* dice : diceList) { - bool result= m_validator->hasValid(dice, true, true); + 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 == OneOfThem) + if(m_conditionType == Dice::OneOfThem) { if(oneIsTrue) { @@ -211,7 +174,7 @@ void IfNode::run(ExecutionNode* previous) nextNode= (nullptr == m_false) ? nullptr : m_false->getCopy(); } } - else if(m_conditionType == AllOfThem) + else if(m_conditionType == Dice::AllOfThem) { if(trueForAll) { @@ -235,14 +198,14 @@ void IfNode::run(ExecutionNode* previous) } } - if(m_conditionType == OnScalar) + if(m_conditionType == Dice::OnScalar) { Die dice; auto val= static_cast<qint64>(value); dice.setValue(val); dice.insertRollValue(val); dice.setMaxValue(val); - if(m_validator->hasValid(&dice, true, true)) + if(m_validatorList->hasValid(&dice, true, true)) { nextNode= m_true; } @@ -269,9 +232,9 @@ void IfNode::run(ExecutionNode* previous) } } -void IfNode::setValidator(Validator* val) +void IfNode::setValidatorList(ValidatorList* val) { - m_validator= val; + m_validatorList= val; } void IfNode::setInstructionTrue(ExecutionNode* node) { @@ -292,7 +255,7 @@ void IfNode::generateDotTree(QString& s) s.append(toString(false)); s.append(" -> "); s.append(m_true->toString(false)); - s.append("[label=\"true" + m_validator->toString() + "\"];\n"); + s.append("[label=\"true" + m_validatorList->toString() + "\"];\n"); m_true->generateDotTree(s); } @@ -357,12 +320,12 @@ ExecutionNode* IfNode::getLeafNode(ExecutionNode* node) return next; } -IfNode::ConditionType IfNode::getConditionType() const +Dice::ConditionType IfNode::getConditionType() const { return m_conditionType; } -void IfNode::setConditionType(const IfNode::ConditionType& conditionType) +void IfNode::setConditionType(const Dice::ConditionType& conditionType) { m_conditionType= conditionType; } @@ -371,9 +334,9 @@ ExecutionNode* IfNode::getCopy() const IfNode* node= new IfNode(); node->setConditionType(m_conditionType); - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - node->setValidator(m_validator->getCopy()); + node->setValidatorList(m_validatorList->getCopy()); } if(nullptr != m_false) { diff --git a/node/ifnode.h b/node/ifnode.h index 55a6051..f0046f0 100644 --- a/node/ifnode.h +++ b/node/ifnode.h @@ -20,10 +20,11 @@ #ifndef IFNODE_H #define IFNODE_H +#include "diceparserhelper.h" #include "executionnode.h" #include "result/diceresult.h" -#include "validator.h" -#include <QDebug> + +class ValidatorList; class PartialDiceRollNode : public ExecutionNode { public: @@ -46,16 +47,6 @@ class IfNode : public ExecutionNode { public: /** - * @brief The ConditionType enum - */ - enum ConditionType - { - OnEach, - OneOfThem, - AllOfThem, - OnScalar - }; - /** * @brief IfNode */ IfNode(); @@ -71,7 +62,7 @@ public: /** * @brief setValidator */ - virtual void setValidator(Validator*); + virtual void setValidatorList(ValidatorList*); /** * @brief setInstructionTrue */ @@ -105,20 +96,20 @@ public: * @brief getConditionType * @return */ - ConditionType getConditionType() const; + Dice::ConditionType getConditionType() const; /** * @brief setConditionType * @param conditionType */ - void setConditionType(const IfNode::ConditionType& conditionType); + void setConditionType(const Dice::ConditionType& conditionType); protected: ExecutionNode* getLeafNode(ExecutionNode* node); protected: - Validator* m_validator; - ConditionType m_conditionType; + ValidatorList* m_validatorList= nullptr; + Dice::ConditionType m_conditionType; ExecutionNode* m_true; ExecutionNode* m_false; diff --git a/node/mergenode.cpp b/node/mergenode.cpp index 575613f..15f2fa7 100644 --- a/node/mergenode.cpp +++ b/node/mergenode.cpp @@ -40,25 +40,22 @@ void MergeNode::run(ExecutionNode* previous) for(auto start : *m_startList) { ExecutionNode* last= getLatestNode(start); - if(nullptr == last) + if(nullptr == last || nullptr == previousLast) continue; auto startResult= start->getResult(); if(nullptr == startResult) continue; - if(nullptr != previousLast) - { - startResult->setPrevious(previousLast->getResult()); - previousLast->setNextNode(start); - } + 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) + if(nullptr == dice) { ///@todo TODO improve here to set homogeneous while is really m_diceResult->setHomogeneous(false); diff --git a/node/occurencecountnode.cpp b/node/occurencecountnode.cpp index 0d69d2a..f82fa35 100644 --- a/node/occurencecountnode.cpp +++ b/node/occurencecountnode.cpp @@ -20,6 +20,7 @@ #include "occurencecountnode.h" #include "result/diceresult.h" #include "result/stringresult.h" +#include "validatorlist.h" #include <QVector> OccurenceCountNode::OccurenceCountNode() : ExecutionNode() {} @@ -106,14 +107,14 @@ void OccurenceCountNode::setHeight(const qint64& height) m_height= height; } -Validator* OccurenceCountNode::getValidator() const +ValidatorList* OccurenceCountNode::getValidatorList() const { - return m_validator; + return m_validatorList; } -void OccurenceCountNode::setValidator(Validator* validator) +void OccurenceCountNode::setValidatorList(ValidatorList* validatorlist) { - m_validator= validator; + m_validatorList= validatorlist; } void OccurenceCountNode::runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec) { @@ -122,11 +123,11 @@ void OccurenceCountNode::runForStringResult(const std::map<qint64, qint64>& mapO QStringList list; for(auto key : mapOccurence) { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { Die die; die.insertRollValue(key.first); - if(!m_validator->hasValid(&die, true)) + if(!m_validatorList->hasValid(&die, true)) continue; } @@ -156,11 +157,11 @@ void OccurenceCountNode::runForDiceResult(const std::map<qint64, qint64>& mapOcc QStringList list; for(auto key : mapOccurence) { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { Die die; die.insertRollValue(key.first); - if(!m_validator->hasValid(&die, true)) + if(!m_validatorList->hasValid(&die, true)) continue; } diff --git a/node/occurencecountnode.h b/node/occurencecountnode.h index 492b295..aa5c2de 100644 --- a/node/occurencecountnode.h +++ b/node/occurencecountnode.h @@ -21,8 +21,8 @@ #define OCCURENCECOUNTNODE_H #include "executionnode.h" -#include "validator.h" +class ValidatorList; class StringResult; class DiceResult; class OccurenceCountNode : public ExecutionNode @@ -42,8 +42,8 @@ public: qint64 getHeight() const; void setHeight(const qint64& height); - Validator* getValidator() const; - void setValidator(Validator* validator); + ValidatorList* getValidatorList() const; + void setValidatorList(ValidatorList* validator); private: void runForStringResult(const std::map<qint64, qint64>& mapOccurence, QVector<qint64>& vec); @@ -52,7 +52,7 @@ private: private: qint64 m_width= 1; qint64 m_height= 0; - Validator* m_validator= nullptr; + ValidatorList* m_validatorList= nullptr; StringResult* m_stringResult= nullptr; DiceResult* m_diceResult= nullptr; }; diff --git a/node/repeaternode.cpp b/node/repeaternode.cpp index 09e88bd..26fab8f 100644 --- a/node/repeaternode.cpp +++ b/node/repeaternode.cpp @@ -26,63 +26,87 @@ #include "parsingtoolbox.h" #include "result/stringresult.h" +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(); auto timeCount= times->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); - auto cmd= m_cmd->getCopy(); + auto cmd= makeCopy(m_cmd); + std::vector<Result*> resultVec; for(int i= 0; i < timeCount; ++i) { - m_cmd->run(this); - auto end= ParsingToolBox::getLeafNode(cmd); - auto result= end->getResult(); + 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 == result) - continue; + if(nullptr == leafResult) + return; - if(result->hasResultOfType(Dice::RESULT_TYPE::SCALAR)) - { - if(m_sumAll) - { - auto res= new ScalarResult(); - - m_result= res; - } - else - { - auto res= new StringResult(); - m_result= res; - } - } - else if(result->hasResultOfType(Dice::RESULT_TYPE::STRING)) - { - auto res= new StringResult(); - - m_result= res; - } - else if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) - { - if(m_sumAll) - { - auto res= new ScalarResult(); - - m_result= res; - } + 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 list; + std::for_each(resultVec.begin(), resultVec.end(), [&list](Result* result) { + auto value= result->getResult(Dice::RESULT_TYPE::SCALAR).toDouble(); + auto diceList= result->getResult(Dice::RESULT_TYPE::DICE_LIST).value<QList<Die*>>(); + auto string= result->getResult(Dice::RESULT_TYPE::STRING).toString(); + + if(!string.isEmpty()) + list.append(string); else { - auto res= new StringResult(); - - m_result= res; + QStringList diceStr; + std::transform(diceList.begin(), diceList.end(), std::back_inserter(diceStr), [](Die* die) { + auto values= die->getListValue(); + + QStringList valuesStr; + std::transform(values.begin(), values.end(), std::back_inserter(valuesStr), + [](qint64 val) { return QString::number(val); }); + + if(valuesStr.size() == 1) + return QStringLiteral("%1").arg(die->getValue()); + else + return QStringLiteral("%1 [%2]").arg(die->getValue()).arg(valuesStr.join(",")); + }); + list.append(QStringLiteral("%1 - Details [%2]").arg(value).arg(diceStr.join(","))); } - } - - cmd= m_cmd->getCopy(); + }); + string->setText(list.join('\n')); + m_result= string; } + + if(nullptr != m_nextNode) + m_nextNode->run(this); } QString RepeaterNode::toString(bool withLabel) const @@ -100,9 +124,9 @@ ExecutionNode* RepeaterNode::getCopy() const return nullptr; } -void RepeaterNode::setCommand(ExecutionNode* cmd) +void RepeaterNode::setCommand(const std::vector<ExecutionNode*>& cmd) { - m_cmd.reset(cmd); + m_cmd= cmd; } void RepeaterNode::setTimeNode(ExecutionNode* time) diff --git a/node/repeaternode.h b/node/repeaternode.h index 847db17..fa1a50a 100644 --- a/node/repeaternode.h +++ b/node/repeaternode.h @@ -35,12 +35,12 @@ public: virtual ExecutionNode* getCopy() const override; - void setCommand(ExecutionNode* node); + void setCommand(const std::vector<ExecutionNode*>& node); void setTimeNode(ExecutionNode* times); void setSumAll(bool b); private: - std::unique_ptr<ExecutionNode> m_cmd; + std::vector<ExecutionNode*> m_cmd; ExecutionNode* m_times= nullptr; bool m_sumAll= false; }; diff --git a/node/rerolldicenode.cpp b/node/rerolldicenode.cpp index 70475a5..370e95e 100644 --- a/node/rerolldicenode.cpp +++ b/node/rerolldicenode.cpp @@ -3,16 +3,16 @@ #include <utility> RerollDiceNode::RerollDiceNode(bool reroll, bool addingMode) - : m_diceResult(new DiceResult()), m_validator(nullptr), m_reroll(reroll), m_adding(addingMode) + : m_diceResult(new DiceResult()), m_validatorList(nullptr), m_reroll(reroll), m_adding(addingMode) { m_result= m_diceResult; } RerollDiceNode::~RerollDiceNode() { - if(nullptr != m_validator) + if(nullptr != m_validatorList) { - delete m_validator; - m_validator= nullptr; + delete m_validatorList; + m_validatorList= nullptr; } } void RerollDiceNode::run(ExecutionNode* previous) @@ -38,8 +38,8 @@ void RerollDiceNode::run(ExecutionNode* previous) for(auto& die : list) { bool finished= false; - auto state - = m_validator->isValidRangeSize(std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())); + 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)) { @@ -51,7 +51,7 @@ void RerollDiceNode::run(ExecutionNode* previous) .arg(static_cast<int>(die->getMaxValue())))); continue; } - while(m_validator->hasValid(die, false) && !finished) + while(m_validatorList->hasValid(die, false) && !finished) { if(m_instruction != nullptr) { @@ -98,15 +98,15 @@ void RerollDiceNode::run(ExecutionNode* previous) } } } -void RerollDiceNode::setValidator(Validator* val) +void RerollDiceNode::setValidatorList(ValidatorList* val) { - m_validator= val; + m_validatorList= val; } QString RerollDiceNode::toString(bool wl) const { if(wl) { - return QString("%1 [label=\"RerollDiceNode validatior: %2\"]").arg(m_id, m_validator->toString()); + return QString("%1 [label=\"RerollDiceNode validatior: %2\"]").arg(m_id, m_validatorList->toString()); } else { @@ -127,7 +127,7 @@ qint64 RerollDiceNode::getPriority() const ExecutionNode* RerollDiceNode::getCopy() const { RerollDiceNode* node= new RerollDiceNode(m_reroll, m_adding); - node->setValidator(m_validator); + node->setValidatorList(m_validatorList); if(nullptr != m_nextNode) { node->setNextNode(m_nextNode->getCopy()); diff --git a/node/rerolldicenode.h b/node/rerolldicenode.h index 32fad79..68b732e 100644 --- a/node/rerolldicenode.h +++ b/node/rerolldicenode.h @@ -3,7 +3,8 @@ #include "executionnode.h" #include "result/diceresult.h" -#include "validator.h" + +class ValidatorList; /** * @brief The RerollDiceNode class reroll dice given a condition and replace(or add) the result. */ @@ -38,7 +39,7 @@ public: /** * @brief setValidator */ - virtual void setValidator(Validator*); + virtual void setValidatorList(ValidatorList*); /** * @brief toString * @return @@ -61,7 +62,7 @@ public: private: DiceResult* m_diceResult= nullptr; - Validator* m_validator= nullptr; + ValidatorList* m_validatorList= nullptr; ExecutionNode* m_instruction= nullptr; const bool m_reroll; diff --git a/node/variablenode.h b/node/variablenode.h index 45133c6..5306ddb 100644 --- a/node/variablenode.h +++ b/node/variablenode.h @@ -11,14 +11,14 @@ class VariableNode : public ExecutionNode { public: VariableNode(); - void run(ExecutionNode* previous); - virtual QString toString(bool withLabel) const; - virtual qint64 getPriority() const; + void run(ExecutionNode* previous) override; + virtual QString toString(bool withLabel) const override; + virtual qint64 getPriority() const override; /** * @brief getCopy * @return */ - virtual ExecutionNode* getCopy() const; + virtual ExecutionNode* getCopy() const override; quint64 getIndex() const; void setIndex(quint64 index); diff --git a/parsingtoolbox.cpp b/parsingtoolbox.cpp index 6ad1c62..02b1130 100644 --- a/parsingtoolbox.cpp +++ b/parsingtoolbox.cpp @@ -19,73 +19,107 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include <QString> +#include "parsingtoolbox.h" +#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/rerolldicenode.h" +#include "node/scalaroperatornode.h" #include "node/sortresult.h" +#include "node/splitnode.h" +#include "node/startingnode.h" #include "node/stringnode.h" +#include "node/uniquenode.h" +#include "node/valueslistnode.h" #include "node/variablenode.h" -#include "parsingtoolbox.h" + +#include <QString> QHash<QString, QString> ParsingToolBox::m_variableHash; -std::vector<ExecutionNode*>* ParsingToolBox::m_startNodes= nullptr; ParsingToolBox::ParsingToolBox() - : m_logicOp(new QMap<QString, BooleanCondition::LogicOperator>()) - , m_logicOperation(new QMap<QString, CompositeValidator::LogicOperation>()) - , m_conditionOperation(new QMap<QString, OperationCondition::ConditionOperator>()) - , m_arithmeticOperation(new QHash<QString, Die::ArithmeticOperator>()) { // m_logicOp = ; - m_logicOp->insert(">=", BooleanCondition::GreaterOrEqual); - m_logicOp->insert("<=", BooleanCondition::LesserOrEqual); - m_logicOp->insert("<", BooleanCondition::LesserThan); - m_logicOp->insert("=", BooleanCondition::Equal); - m_logicOp->insert(">", BooleanCondition::GreaterThan); - m_logicOp->insert("!=", BooleanCondition::Different); + m_logicOp.insert(">=", BooleanCondition::GreaterOrEqual); + m_logicOp.insert("<=", BooleanCondition::LesserOrEqual); + m_logicOp.insert("<", BooleanCondition::LesserThan); + m_logicOp.insert("=", BooleanCondition::Equal); + m_logicOp.insert(">", BooleanCondition::GreaterThan); + m_logicOp.insert("!=", BooleanCondition::Different); // m_logicOperation = ; - m_logicOperation->insert("|", CompositeValidator::OR); - m_logicOperation->insert("^", CompositeValidator::EXCLUSIVE_OR); - m_logicOperation->insert("&", CompositeValidator::AND); + m_logicOperation.insert("|", ValidatorList::OR); + m_logicOperation.insert("^", ValidatorList::EXCLUSIVE_OR); + m_logicOperation.insert("&", ValidatorList::AND); // m_conditionOperation = ; - m_conditionOperation->insert("%", OperationCondition::Modulo); + m_conditionOperation.insert("%", OperationCondition::Modulo); // m_arithmeticOperation = new QHash<QString,ScalarOperatorNode::ArithmeticOperator>(); - m_arithmeticOperation->insert(QStringLiteral("+"), Die::PLUS); - m_arithmeticOperation->insert(QStringLiteral("-"), Die::MINUS); - m_arithmeticOperation->insert(QStringLiteral("*"), Die::MULTIPLICATION); - m_arithmeticOperation->insert(QStringLiteral("x"), Die::MULTIPLICATION); - m_arithmeticOperation->insert(QStringLiteral("|"), Die::INTEGER_DIVIDE); - m_arithmeticOperation->insert(QStringLiteral("/"), Die::DIVIDE); - m_arithmeticOperation->insert(QStringLiteral("÷"), Die::DIVIDE); - m_arithmeticOperation->insert(QStringLiteral("**"), Die::POW); + m_arithmeticOperation.insert(QStringLiteral("+"), Die::PLUS); + m_arithmeticOperation.insert(QStringLiteral("-"), Die::MINUS); + m_arithmeticOperation.insert(QStringLiteral("**"), Die::POW); + m_arithmeticOperation.insert(QStringLiteral("*"), Die::MULTIPLICATION); + m_arithmeticOperation.insert(QStringLiteral("x"), Die::MULTIPLICATION); + m_arithmeticOperation.insert(QStringLiteral("|"), Die::INTEGER_DIVIDE); + m_arithmeticOperation.insert(QStringLiteral("/"), Die::DIVIDE); + m_arithmeticOperation.insert(QStringLiteral("÷"), Die::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_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() +ParsingToolBox::~ParsingToolBox() {} + +void ParsingToolBox::clearUp() { - if(nullptr != m_logicOp) - { - delete m_logicOp; - m_logicOp= nullptr; - } - if(nullptr != m_logicOperation) - { - delete m_logicOperation; - m_logicOperation= nullptr; - } - if(nullptr != m_conditionOperation) - { - delete m_conditionOperation; - m_conditionOperation= nullptr; - } - if(nullptr != m_arithmeticOperation) - { - delete m_arithmeticOperation; - m_arithmeticOperation= nullptr; - } + m_errorMap.clear(); + m_comment= QString(""); } ExecutionNode* ParsingToolBox::addSort(ExecutionNode* e, bool b) { @@ -94,11 +128,27 @@ ExecutionNode* ParsingToolBox::addSort(ExecutionNode* e, bool b) e->setNextNode(nodeSort); return nodeSort; } - +ExecutionNode* ParsingToolBox::getLeafNode(ExecutionNode* start) +{ + ExecutionNode* next= start; + while(nullptr != next->getNextNode()) + { + next= next->getNextNode(); + } + return next; +} +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, OperationCondition::ConditionOperator& op) { QString longKey; - auto const& keys= m_conditionOperation->keys(); + auto const& keys= m_conditionOperation.keys(); for(const QString& tmp : keys) { if(str.startsWith(tmp)) @@ -112,7 +162,7 @@ bool ParsingToolBox::readDiceLogicOperator(QString& str, OperationCondition::Con if(longKey.size() > 0) { str= str.remove(0, longKey.size()); - op= m_conditionOperation->value(longKey); + op= m_conditionOperation.value(longKey); return true; } @@ -124,7 +174,7 @@ bool ParsingToolBox::readArithmeticOperator(QString& str, Die::ArithmeticOperato bool found= false; // QHash<QString,ScalarOperatorNode::ArithmeticOperator>::Iterator - for(auto i= m_arithmeticOperation->begin(); i != m_arithmeticOperation->end() && !found; ++i) + for(auto i= m_arithmeticOperation.begin(); i != m_arithmeticOperation.end() && !found; ++i) { if(str.startsWith(i.key())) { @@ -139,7 +189,7 @@ bool ParsingToolBox::readArithmeticOperator(QString& str, Die::ArithmeticOperato bool ParsingToolBox::readLogicOperator(QString& str, BooleanCondition::LogicOperator& op) { QString longKey; - auto const& keys= m_logicOp->keys(); + auto const& keys= m_logicOp.keys(); for(const QString& tmp : keys) { if(str.startsWith(tmp)) @@ -153,13 +203,29 @@ bool ParsingToolBox::readLogicOperator(QString& str, BooleanCondition::LogicOper if(longKey.size() > 0) { str= str.remove(0, longKey.size()); - op= m_logicOp->value(longKey); + 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; @@ -168,7 +234,7 @@ bool ParsingToolBox::readOperand(QString& str, ExecutionNode*& node) { VariableNode* variableNode= new VariableNode(); variableNode->setIndex(static_cast<quint64>(intValue - 1)); - variableNode->setData(m_startNodes); + variableNode->setData(&m_startNodes); node= variableNode; return true; } @@ -192,6 +258,7 @@ bool ParsingToolBox::readOperand(QString& str, ExecutionNode*& node) Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) { Validator* returnVal= nullptr; + auto opCompare= readConditionType(str); BooleanCondition::LogicOperator myLogicOp= BooleanCondition::Equal; readLogicOperator(str, myLogicOp); @@ -203,6 +270,7 @@ Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) 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); @@ -229,6 +297,7 @@ Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) str= str.remove(0, 1); qint64 start= operandNode->getScalarResult(); Range* range= new Range(); + range->setConditionType(opCompare); range->setValue(start, end); returnVal= range; isRange= true; @@ -238,6 +307,7 @@ Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) if(!isRange) { BooleanCondition* condition= new BooleanCondition(); + condition->setConditionType(opCompare); condition->setValueNode(operandNode); condition->setOperator(myLogicOp); returnVal= condition; @@ -245,28 +315,32 @@ Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) } return returnVal; } -IfNode::ConditionType ParsingToolBox::readConditionType(QString& str) + +Dice::ConditionType ParsingToolBox::readConditionType(QString& str) { - IfNode::ConditionType type= IfNode::OnEach; + Dice::ConditionType type= Dice::OnEach; if(str.startsWith('.')) { str= str.remove(0, 1); - type= IfNode::OneOfThem; + type= Dice::OneOfThem; } else if(str.startsWith('*')) { str= str.remove(0, 1); - type= IfNode::AllOfThem; + type= Dice::AllOfThem; } else if(str.startsWith(':')) { str= str.remove(0, 1); - type= IfNode::OnScalar; + type= Dice::OnScalar; } return type; } - -Validator* ParsingToolBox::readCompositeValidator(QString& str) +bool ParsingToolBox::hasError() const +{ + return !m_errorMap.isEmpty(); +} +ValidatorList* ParsingToolBox::readValidatorList(QString& str) { bool expectSquareBrasket= false; if((str.startsWith("["))) @@ -275,9 +349,9 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) expectSquareBrasket= true; } Validator* tmp= readValidator(str, expectSquareBrasket); - CompositeValidator::LogicOperation opLogic; + ValidatorList::LogicOperation opLogic; - QVector<CompositeValidator::LogicOperation> operators; + QVector<ValidatorList::LogicOperation> operators; QList<Validator*> validatorList; while(nullptr != tmp) @@ -296,24 +370,15 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) str= str.remove(0, 1); // isOk=true; } - - if(!validatorList.isEmpty()) - { - validatorList.append(tmp); - } - else - { - operators.clear(); - return tmp; - } + validatorList.append(tmp); tmp= nullptr; } } if(!validatorList.isEmpty()) { - CompositeValidator* validator= new CompositeValidator(); + ValidatorList* validator= new ValidatorList(); validator->setOperationList(operators); - validator->setValidatorList(validatorList); + validator->setValidators(validatorList); return validator; } else @@ -321,10 +386,10 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) return nullptr; } } -bool ParsingToolBox::readLogicOperation(QString& str, CompositeValidator::LogicOperation& op) +bool ParsingToolBox::readLogicOperation(QString& str, ValidatorList::LogicOperation& op) { QString longKey; - auto const& keys= m_logicOperation->keys(); + auto const& keys= m_logicOperation.keys(); for(auto& tmp : keys) { if(str.startsWith(tmp)) @@ -338,7 +403,7 @@ bool ParsingToolBox::readLogicOperation(QString& str, CompositeValidator::LogicO if(longKey.size() > 0) { str= str.remove(0, longKey.size()); - op= m_logicOperation->value(longKey); + op= m_logicOperation.value(longKey); return true; } @@ -412,16 +477,11 @@ ExecutionNode* ParsingToolBox::getLatestNode(ExecutionNode* node) return next; } -std::vector<ExecutionNode*>* ParsingToolBox::getStartNodes() +const std::vector<ExecutionNode*>& ParsingToolBox::getStartNodes() { return m_startNodes; } -void ParsingToolBox::setStartNodes(std::vector<ExecutionNode*>* startNodes) -{ - m_startNodes= startNodes; -} - bool ParsingToolBox::readString(QString& str, QString& strResult) { if(str.isEmpty()) @@ -596,7 +656,7 @@ bool ParsingToolBox::readAscending(QString& str) } return false; } -Dice::CONDITION_STATE ParsingToolBox::isValidValidator(ExecutionNode* previous, Validator* val) +Dice::CONDITION_STATE ParsingToolBox::isValidValidator(ExecutionNode* previous, ValidatorList* val) { DiceRollerNode* node= getDiceRollerNode(previous); if(nullptr == node) @@ -895,7 +955,6 @@ QString ParsingToolBox::replacePlaceHolderToValue(const QString& source, const Q // return source; } - void ParsingToolBox::readSubtitutionParameters(SubtituteInfo& info, QString& rest) { auto sizeS= rest.size(); @@ -915,6 +974,951 @@ void ParsingToolBox::readSubtitutionParameters(SubtituteInfo& info, QString& res info.setLength(info.length() + sizeS - rest.size()); } +bool ParsingToolBox::readReaperArguments(RepeaterNode* node, QString& source) +{ + if(readOpenParentheses(source)) + { + auto instructions= readInstructionList(source, false); + if(!instructions.empty()) + { + 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::getLatestNode(operandNode); + // ExecutionNode* operatorNode=nullptr; + while(readOperator(str, operandNode)) + { + // operandNode->setNextNode(operatorNode); + operandNode= ParsingToolBox::getLatestNode(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("[")) + { + str= str.remove(0, 1); + int pos= ParsingToolBox::findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]"); + if(-1 != pos) + { + QString liststr= str.left(pos); + auto list= liststr.split(","); + str= str.remove(0, pos + 1); + auto values= new ValuesListNode(); + for(auto var : list) + { + qint64 number= 1; + QString error; + 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; + } + } + return false; +} +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; + } + + ExecutionNode* node= nullptr; + 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: + { + qint64 myNumber= 0; + bool ascending= readAscending(str); + + if(readNumber(str, myNumber)) + { + node= addSort(previous, ascending); + KeepDiceExecNode* nodeK= new KeepDiceExecNode(); + nodeK->setDiceKeepNumber(myNumber); + node->setNextNode(nodeK); + node= nodeK; + found= true; + } + } + break; + case KeepAndExplode: + { + qint64 myNumber= 0; + bool ascending= readAscending(str); + if(readNumber(str, myNumber)) + { + /* if(!hasDice) + { + previous = addRollDiceNode(DEFAULT_FACES_NUMBER,previous); + }*/ + DiceRollerNode* nodeTmp= dynamic_cast<DiceRollerNode*>(previous); + if(nullptr != nodeTmp) + { + previous= addExplodeDiceNode(static_cast<qint64>(nodeTmp->getFaces()), previous); + } + + node= addSort(previous, ascending); + + KeepDiceExecNode* nodeK= new KeepDiceExecNode(); + nodeK->setDiceKeepNumber(myNumber); + + 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); + node= filterNode; + found= true; + } + } + break; + case Sort: + { + bool ascending= readAscending(str); + node= 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); + node= 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); + node= 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); + node= 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); + node= mergeNode; + found= true; + } + break; + case AllSameExplode: + { + AllSameNode* allSame= new AllSameNode(); + previous->setNextNode(allSame); + node= allSame; + found= true; + } + break; + case Bind: + { + BindNode* bindNode= new BindNode(); + bindNode->setStartList(&m_startNodes); + previous->setNextNode(bindNode); + node= 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); + node= occNode; + found= true; + } + break; + case Unique: + { + 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); + node= 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); + node= nodeif; + found= true; + } + else + { + delete nodeif; + } + } + else + { + delete nodeif; + } + break; + } + case Split: + { + SplitNode* splitnode= new SplitNode(); + previous->setNextNode(splitnode); + node= splitnode; + found= true; + } + break; + case Group: + { + qint64 groupNumber= 0; + if(readNumber(str, groupNumber)) + { + GroupNode* groupNode= new GroupNode(); + groupNode->setGroupValue(groupNumber); + previous->setNextNode(groupNode); + node= groupNode; + found= true; + } + } + break; + } + } + } + return found; +} +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(BooleanCondition::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::readBlocInstruction(QString& str, ExecutionNode*& resultnode) +{ + if(str.startsWith('{')) + { + str= str.remove(0, 1); + ExecutionNode* node= nullptr; + Die::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; + Die::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::getLatestNode(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::getLatestNode(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) + { + lsrNode->setUnique(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 : 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) +{ + if(str.isEmpty() || nullptr == previous) + { + return false; + } + + Die::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 false; + } + 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); + + return true; + } + else + { + delete node; + } + } + else + { + while(readOption(str, previous)) + { + previous= ParsingToolBox::getLatestNode(previous); + } + } + return false; +} +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; +} + +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::getLatestNode(latest); + keepParsing= !str.isEmpty(); + while(keepParsing) + { + auto before= str; + if(readOperator(str, latest)) + { + latest= ParsingToolBox::getLatestNode(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; diff --git a/result/diceresult.cpp b/result/diceresult.cpp index 23b925e..083c683 100644 --- a/result/diceresult.cpp +++ b/result/diceresult.cpp @@ -73,7 +73,7 @@ QVariant DiceResult::getResult(Dice::RESULT_TYPE type) } case Dice::RESULT_TYPE::DICE_LIST: { - return QVariant(); + return QVariant::fromValue(m_diceValues); } default: break; diff --git a/result/diceresult.h b/result/diceresult.h index ce8ffb7..8f30340 100644 --- a/result/diceresult.h +++ b/result/diceresult.h @@ -92,5 +92,5 @@ private: bool m_homogeneous; Die::ArithmeticOperator m_operator; }; - +Q_DECLARE_METATYPE(QList<Die*>) #endif // DICERESULT_H diff --git a/tests/dice/CMakeLists.txt b/tests/dice/CMakeLists.txt index d254624..e2e580a 100644 --- a/tests/dice/CMakeLists.txt +++ b/tests/dice/CMakeLists.txt @@ -1,12 +1,14 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra") set(CMAKE_AUTOMOC ON) -find_package(Qt5Test REQUIRED) +find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Svg Test) set(test_source testnode.cpp tst_dice.cpp) -add_executable(test_dice ${test_source} ${dice_sources}) +add_executable(test_dice ${test_source}) -target_include_directories(test_dice PRIVATE ../../include) +target_include_directories(test_dice PRIVATE ../../include ../../ ../../node ../../result) -target_link_libraries(test_dice Qt5::Test) +find_library(DICEPARSER_LIBRARY diceparser HINTS ${CMAKE_CURRENT_BINARY_DIR}/../../) + +target_link_libraries(test_dice PUBLIC Qt5::Core Qt5::Gui Qt5::Test diceparser_shared) add_test(tst_diceparser test_dice) diff --git a/tests/dice/tst_dice.cpp b/tests/dice/tst_dice.cpp index 757969f..8eed852 100644 --- a/tests/dice/tst_dice.cpp +++ b/tests/dice/tst_dice.cpp @@ -44,8 +44,57 @@ #include "node/stringnode.h" #include "node/uniquenode.h" #include "operationcondition.h" +#include "parsingtoolbox.h" #include "result/stringresult.h" #include "testnode.h" +#include "validatorlist.h" + +void makeResult(DiceResult& result, const QVector<int>& values, const QVector<int>& subvalues= QVector<int>(), + int base= 1, int max= 10) +{ + int i= 0; + for(int val : values) + { + auto die= new Die(); + die->setBase(base); + die->setMaxValue(max); + die->insertRollValue(val); + if(i == 0 && !subvalues.empty()) + { + for(int sval : subvalues) + { + die->insertRollValue(sval); + } + } + result.insertResult(die); + ++i; + } +} + +void makeResultExplode(DiceResult& result, const QVector<int>& values) +{ + auto die= new Die(); + die->setBase(1); + die->setMaxValue(10); + for(int val : values) + { + die->insertRollValue(val); + } + result.insertResult(die); +} + +ValidatorList* makeValidator(int number, BooleanCondition::LogicOperator op) +{ + BooleanCondition* validator= new BooleanCondition(); + NumberNode* node= new NumberNode(); + node->setNumber(number); + validator->setValueNode(node); + validator->setOperator(op); + + ValidatorList* list= new ValidatorList(); + list->setValidators(QList<Validator*>() << validator); + return list; +} class TestDice : public QObject { @@ -57,6 +106,10 @@ public: private slots: void init(); void getAndSetTest(); + + void validatorListTest(); + void validatorListTest_data(); + void diceRollD10Test(); void diceRollD20Test(); void commandEndlessLoop(); @@ -138,6 +191,7 @@ private slots: private: std::unique_ptr<Die> m_die; std::unique_ptr<DiceParser> m_diceParser; + std::unique_ptr<ParsingToolBox> m_parsingToolBox; }; TestDice::TestDice() {} @@ -146,6 +200,7 @@ void TestDice::init() { m_die.reset(new Die()); m_diceParser.reset(new DiceParser()); + m_parsingToolBox.reset(new ParsingToolBox()); } void TestDice::getAndSetTest() @@ -163,6 +218,34 @@ void TestDice::getAndSetTest() QVERIFY(m_die->isSelected() == false); } +void TestDice::validatorListTest() +{ + QFETCH(QString, cmd); + QFETCH(int, result); + + auto parsing= m_diceParser->parseLine(cmd); + QVERIFY2(parsing, "parsing"); + + m_diceParser->start(); + QVERIFY2(m_diceParser->humanReadableError().isEmpty(), "no error"); + QVERIFY2(m_diceParser->humanReadableWarning().isEmpty(), "no warning"); + + auto resultCmd= m_diceParser->getLastIntegerResults(); + + QCOMPARE(resultCmd.size(), 1); + + QCOMPARE(resultCmd.first(), result); +} + +void TestDice::validatorListTest_data() +{ + QTest::addColumn<QString>("cmd"); + QTest::addColumn<int>("result"); + + QTest::addRow("cmd1") << "2d[6-6]c6" << 2; + QTest::addRow("cmd2") << "[6,2]c[:>6&%2=0]" << 2; +} + void TestDice::diceRollD10Test() { m_die->setMaxValue(10); @@ -183,6 +266,7 @@ void TestDice::diceRollD20Test() QVERIFY(m_die->getValue() < 21); } } + void TestDice::commandEndlessLoop() { bool a= m_diceParser->parseLine("1D10e[>0]"); @@ -373,14 +457,14 @@ void TestDice::scopeDF_data() } void TestDice::testAlias() { - m_diceParser->insertAlias(new DiceAlias("!", "3d6c"), 0); - m_diceParser->insertAlias(new DiceAlias("g", "d10k"), 1); - m_diceParser->insertAlias(new DiceAlias("(.*)C(.*)", QStringLiteral("\\1d10e10c[>=\\2]"), false), 2); + m_parsingToolBox->insertAlias(new DiceAlias("!", "3d6c"), 0); + m_parsingToolBox->insertAlias(new DiceAlias("g", "d10k"), 1); + m_parsingToolBox->insertAlias(new DiceAlias("(.*)C(.*)", QStringLiteral("\\1d10e10c[>=\\2]"), false), 2); QFETCH(QString, cmd); QFETCH(QString, expected); - auto result= m_diceParser->convertAlias(cmd); + auto result= m_parsingToolBox->convertAlias(cmd); QCOMPARE(result, expected); } @@ -452,12 +536,9 @@ void TestDice::dangerousCommandsTest() { QFETCH(QString, cmd); - for(int i= 0; i < 1000; ++i) - { - auto b= m_diceParser->parseLine(cmd); - QVERIFY(b); - m_diceParser->start(); - } + auto b= m_diceParser->parseLine(cmd); + QVERIFY(b); + m_diceParser->start(); } void TestDice::dangerousCommandsTest_data() { @@ -470,50 +551,6 @@ void TestDice::dangerousCommandsTest_data() // QTest::addRow("cmd5") << "10d10g10"; } -void makeResult(DiceResult& result, const QVector<int>& values, const QVector<int>& subvalues= QVector<int>(), - int base= 1, int max= 10) -{ - int i= 0; - for(int val : values) - { - auto die= new Die(); - die->setBase(base); - die->setMaxValue(max); - die->insertRollValue(val); - if(i == 0 && !subvalues.empty()) - { - for(int sval : subvalues) - { - die->insertRollValue(sval); - } - } - result.insertResult(die); - ++i; - } -} - -void makeResultExplode(DiceResult& result, const QVector<int>& values) -{ - auto die= new Die(); - die->setBase(1); - die->setMaxValue(10); - for(int val : values) - { - die->insertRollValue(val); - } - result.insertResult(die); -} - -Validator* makeValidator(int number, BooleanCondition::LogicOperator op) -{ - BooleanCondition* validator= new BooleanCondition(); - NumberNode* node= new NumberNode(); - node->setNumber(number); - validator->setValueNode(node); - validator->setOperator(op); - return validator; -} - void TestDice::keepTest() { QFETCH(QVector<int>, values); @@ -618,7 +655,7 @@ void TestDice::countTest() auto validator= makeValidator(condition, BooleanCondition::GreaterThan); - countN.setValidator(validator); + countN.setValidatorList(validator); DiceResult result; node.setResult(&result); node.setNextNode(&countN); @@ -629,7 +666,7 @@ void TestDice::countTest() QCOMPARE(score, countN.getResult()->getResult(Dice::RESULT_TYPE::SCALAR).toInt()); - countN.setValidator(nullptr); + countN.setValidatorList(nullptr); } void TestDice::countTest_data() @@ -658,7 +695,7 @@ void TestDice::rerollTest() node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::GreaterThan); - reroll.setValidator(validator); + reroll.setValidatorList(validator); node.setNextNode(&reroll); node.run(nullptr); @@ -702,7 +739,7 @@ void TestDice::explodeTest() node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::Equal); - explode.setValidator(validator); + explode.setValidatorList(validator); node.setNextNode(&explode); node.run(nullptr); @@ -746,7 +783,7 @@ void TestDice::rerollUntilTest() node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::Equal); - reroll.setValidator(validator); + reroll.setValidatorList(validator); node.setNextNode(&reroll); node.run(nullptr); @@ -788,7 +825,7 @@ void TestDice::rerollAddTest() node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::Equal); - reroll.setValidator(validator); + reroll.setValidatorList(validator); node.setNextNode(&reroll); node.run(nullptr); @@ -827,7 +864,7 @@ void TestDice::ifTest() QFETCH(int, valCondition); QFETCH(QString, expectedResult); - IfNode::ConditionType conditionType= static_cast<IfNode::ConditionType>(condition); + Dice::ConditionType conditionType= static_cast<Dice::ConditionType>(condition); TestNode node; IfNode ifNode; @@ -846,16 +883,12 @@ void TestDice::ifTest() ifNode.setInstructionFalse(&falseNode); auto validator= makeValidator(valCondition, BooleanCondition::Equal); - ifNode.setValidator(validator); + ifNode.setValidatorList(validator); node.setNextNode(&ifNode); node.run(nullptr); - QString text; - if(nullptr != ifNode.getNextNode()) - text= dynamic_cast<StringResult*>(ifNode.getNextNode()->getResult())->getText(); - else - text= dynamic_cast<StringResult*>(ifNode.getResult())->getText(); + auto text= dynamic_cast<StringResult*>(ifNode.getNextNode()->getResult())->getText(); QCOMPARE(expectedResult, text); @@ -893,39 +926,34 @@ void TestDice::paintTest_data() {} void TestDice::filterTest() { - QFETCH(QVector<int>, values); - QFETCH(int, condition); - QFETCH(bool, different); - - TestNode node; - FilterNode filter; - - DiceResult result; - makeResult(result, values); - node.setResult(&result); + QFETCH(QString, cmd); + QFETCH(int, result); - auto validator= makeValidator(condition, BooleanCondition::Different); - filter.setValidator(validator); - node.setNextNode(&filter); + auto parsing= m_diceParser->parseLine(cmd); + QVERIFY2(parsing, "parsing"); - node.run(nullptr); + m_diceParser->start(); + QVERIFY2(m_diceParser->humanReadableError().isEmpty(), "no error"); + QVERIFY2(m_diceParser->humanReadableWarning().isEmpty(), "no warning"); - auto list= dynamic_cast<DiceResult*>(filter.getResult())->getResultList(); + auto resultCmd= m_diceParser->getLastIntegerResults(); - auto expected= result.getResultList(); - bool resultDiff= (list.size() != expected.size()); + QCOMPARE(resultCmd.size(), 1); - QCOMPARE(different, resultDiff); + QCOMPARE(resultCmd.first(), result); } void TestDice::filterTest_data() { - QTest::addColumn<QVector<int>>("values"); - QTest::addColumn<int>("condition"); - QTest::addColumn<bool>("different"); - - QTest::addRow("cmd1") << QVector<int>({8, 4, 2}) << 4 << true; - QTest::addRow("cmd2") << QVector<int>({0, 0, 0}) << 1 << false; + QTest::addColumn<QString>("cmd"); + QTest::addColumn<int>("result"); + + QTest::addRow("cmd1") << "[8, 4, 2]f4" << 4; + QTest::addRow("cmd2") << "[0, 0, 0]f1" << 0; + QTest::addRow("cmd3") << "[1, 2, 3]f[.>2&:>5]" << 6; + QTest::addRow("cmd4") << "[1, 2, 6]f[.<2&>5]" << 6; + QTest::addRow("cmd5") << "[2, 2, 6]f[.<2&>5]" << 0; + QTest::addRow("cmd5") << "[1, 5, 1]f[.<2&>5]" << 0; } void TestDice::uniqueTest() @@ -1008,7 +1036,7 @@ void TestDice::occurenceTest() node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::GreaterThan); - count.setValidator(validator); + count.setValidatorList(validator); node.setNextNode(&count); node.run(nullptr); diff --git a/validator.cpp b/validator.cpp index 9f717f8..3d0b7af 100644 --- a/validator.cpp +++ b/validator.cpp @@ -24,7 +24,91 @@ 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::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::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/validator.h b/validator.h index a1e7d65..c9f0b4c 100644 --- a/validator.h +++ b/validator.h @@ -31,6 +31,7 @@ * @brief The Validator class is an abstract class for checking the validity of dice for some * operator. */ +// template <Dice::ConditionType C> class Validator { public: @@ -66,11 +67,38 @@ public: * @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 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/validatorlist.cpp b/validatorlist.cpp new file mode 100644 index 0000000..0d0abb5 --- /dev/null +++ b/validatorlist.cpp @@ -0,0 +1,355 @@ +/*************************************************************************** + * 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 "diceresult.h" +#include "result.h" +#include "validator.h" +#include <utility> + +bool isValid(Die* die, const ValidatorResult& diceList, ValidatorList::LogicOperation op) +{ + if(op == ValidatorList::OR) + return true; + + bool newResult= false; + + if(diceList.m_allTrue) + { + newResult= true; + } + else + { + auto it= std::find_if(diceList.m_validDice.begin(), diceList.m_validDice.end(), + [die](const std::pair<Die*, qint64>& pair) { return die == pair.first; }); + if(it != diceList.m_validDice.end()) + newResult= true; + } + + if(op == ValidatorList::EXCLUSIVE_OR) + return !newResult; + + return newResult; +} + +DiceResult* getDiceResult(Result* result) +{ + auto dice= dynamic_cast<DiceResult*>(result); + if(nullptr == dice) + { + qFatal("Error, no dice result"); + // TODO: manage error here. + } + return dice; +} + +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 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 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; +} + +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 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 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 ValidatorList::setOperationList(const QVector<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({{}, false}); + 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.m_allTrue= true; + } + } + break; + case Dice::OnEach: + { + DiceResult* diceResult= getDiceResult(result); + if(nullptr == diceResult) + break; + for(auto die : diceResult->getResultList()) + { + auto score= validator->hasValid(die, recursive, unlight); + if(score) + { + validResult.m_validDice.push_back({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.m_allTrue= true; + } + } + 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.m_allTrue= true; + } + } + } + validityData.push_back(validResult); + } + if(validityData.empty()) + return; + + std::size_t i= 0; + ValidatorResult finalResult({{}, false}); + { + auto vec= validityData[i]; + finalResult.m_validDice.reserve(vec.m_validDice.size()); + finalResult= vec; + } + ++i; + for(auto op : m_operators) + { + ValidatorResult tmpResult({{}, false}); + if(validityData.size() > i) + { + auto vec= validityData[i]; + + auto bigger= (vec > finalResult) ? vec : finalResult; + auto smaller= (vec > finalResult) ? finalResult : vec; + + if(bigger.m_allTrue && smaller.m_allTrue) + tmpResult.m_allTrue= true; + for(auto die : bigger.m_validDice) + { + if(isValid(die.first, smaller, op)) + { + tmpResult.m_validDice.push_back(die); + } + } + finalResult= tmpResult; + } + } + + if(finalResult.m_allTrue) + { + DiceResult* diceResult= getDiceResult(result); + if(nullptr == diceResult) + return; + auto diceList= diceResult->getResultList(); + std::transform(diceList.begin(), diceList.end(), std::back_inserter(finalResult.m_validDice), [](Die* die) { + return std::pair<Die*, qint64>({die, 0}); + }); + } + + for(auto die : finalResult.m_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/validatorlist.h b/validatorlist.h new file mode 100644 index 0000000..5d29817 --- /dev/null +++ b/validatorlist.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * 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 "diceparserhelper.h" +#include <functional> + +class Validator; +class Die; +class Result; + +struct ValidatorResult +{ + std::vector<std::pair<Die*, qint64>> m_validDice; + bool m_allTrue; + + 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: + enum LogicOperation + { + OR, + EXCLUSIVE_OR, + AND, + NONE + }; + + ValidatorList(); + virtual ~ValidatorList(); + + virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const; + + void setOperationList(const QVector<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<LogicOperation> m_operators; + QList<Validator*> m_validatorList; +}; + +#endif // VALIDATORLIST_H |