diff options
| author | 2019-07-29 20:35:52 +0000 | |
|---|---|---|
| committer | 2019-07-29 20:35:52 +0000 | |
| commit | 1a902d383eef1e042d4462cd07b9384fcdf4d118 (patch) | |
| tree | 766b8ab720fa5da11730d2fc2388f51b9d14de49 | |
| parent | f5906125576a8323a731c9456ce3dfc53b67ef59 (diff) | |
| parent | 0d4b68221bda594cc695d216dfa21306ddb69c85 (diff) | |
| download | OneRoll-1a902d383eef1e042d4462cd07b9384fcdf4d118.tar.gz OneRoll-1a902d383eef1e042d4462cd07b9384fcdf4d118.zip | |
Merge branch 'liberation' into 'master'
Add fuzzer on the DiceParser
See merge request kde/rolisteam-diceparser!2
63 files changed, 1060 insertions, 525 deletions
@@ -20,3 +20,8 @@ qrc_*.cpp Makefile *-build-* build* + +*crashes* +*hangs* +*queue* +*fuzzer0* diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a9a340..f213bc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -project(diceparser) +project(diceparser VERSION 1.9.0 DESCRIPTION "Parser of dice command") set(QT_REQUIRED_VERSION "5.12.0") find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core Test Gui Svg) @@ -9,55 +9,91 @@ enable_testing(true) include_directories(${CMAKE_CURRENT_SOURCE_DIR} result node) 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/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 + ${CMAKE_CURRENT_SOURCE_DIR}/diceparser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/range.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/booleancondition.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/validator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/compositevalidator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operationcondition.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/die.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parsingtoolbox.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dicealias.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/result/result.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/result/scalarresult.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/result/stringresult.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/result/diceresult.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/countexecutenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/dicerollernode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/executionnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/explodedicenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/helpnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/mergenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/jumpbackwardnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/keepdiceexecnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/listaliasnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/listsetrollnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/numbernode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/parenthesesnode.cpp + # ${CMAKE_CURRENT_SOURCE_DIR}/ node/forloopnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/paintnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/rerolldicenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/scalaroperatornode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/sortresult.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/startingnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/filternode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/stringnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/ifnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/splitnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/groupnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/bind.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/occurencecountnode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/uniquenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/highlightdice.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/variablenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/node/valueslistnode.cpp ) -add_library(diceparser SHARED ${dice_sources} ) -target_link_libraries(diceparser PUBLIC Qt5::Core Qt5::Gui Qt5::Svg) +IF(STATIC_BUILD) + add_library(diceparser_static STATIC ${dice_sources} ) + target_include_directories(diceparser_static PRIVATE include) + SET_TARGET_PROPERTIES(diceparser_static PROPERTIES OUTPUT_NAME diceparser CLEAN_DIRECT_OUTPUT 1) + target_link_libraries(diceparser_static PUBLIC Qt5::Core Qt5::Gui Qt5::Svg) + install(TARGETS diceparser_static + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +set(documentation README.md HelpMe.md) + +add_library(diceparser_shared SHARED ${dice_sources} ${documentation}) + +target_include_directories(diceparser_shared PRIVATE include) + + +SET_TARGET_PROPERTIES(diceparser_shared PROPERTIES OUTPUT_NAME diceparser CLEAN_DIRECT_OUTPUT 1) +target_link_libraries(diceparser_shared PUBLIC Qt5::Core Qt5::Gui Qt5::Svg) + +set_target_properties(diceparser_shared PROPERTIES VERSION ${PROJECT_VERSION}) +set_target_properties(diceparser_shared PROPERTIES SOVERSION 1) + +set_target_properties(diceparser_shared PROPERTIES PUBLIC_HEADER "include/diceparser.h;include/highlightdice.h;include/parsingtoolbox.h;include/dicealias.h;include/diceparserhelper.h") add_subdirectory(cli) add_subdirectory( tests ) #add_subdirectory(irc) #add_subdirectory(mobile) #add_subdirectory(webserver) + + +include(GNUInstallDirs) + +install(TARGETS diceparser_shared + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + +configure_file(diceparser.pc.in diceparser.pc @ONLY) + +install(FILES ${CMAKE_BINARY_DIR}/diceparser.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) + + + @@ -59,44 +59,111 @@ More examples at : https://github.com/Rolisteam/DiceParser/blob/master/HelpMe.md The grammar is something like this: ``` -Command =: Instruction [';',Instruction]* -Instruction =: Expression -Expression =: number | number Dice DiceOperation | ScalarOperator Expression | string | variable Expression -Dice =: DiceOperator Number(faces) | DiceOperator ListOfValues -DiceOperator =: D | L -DiceOperation =: Keep | KeepAndExplode | Sort | Count | Reroll | RerollUntil | If | Explode | Jumpbackward | Merge | Filter | Split | Parenthese | Count | Paint | Group +Program =: Instruction [InstructionSeparator, Instruction]* Comment +InstructionSeparator = ; +Instruction =: Expression ([Operator, Expression]* | [Option]*) +Operator =: ScalarOperator +Expression =: OpenParenthesis Expression closeParenthesis +| Option* +| [Operator, Expression]* +| Operand Dice +| Command +| NodeOperator [Option]* +| ValuesList +| Dice (Operand == 1) +Operand =: DynamicVariable | Number | String +OpenParenthesis = ( +closeParenthesis = ) +OpenList = [ +CloseList = ] +ListSeparator = , +ValuesList=: OpenList (DynamicVariable | Number)? [ ListSeparator,(DynamicVariable | Number)]* CloseList +Dice =: DiceOperator [uniqueValue] DiceParameter +DiceOperator =: D ParameterDice | L ParameterList +DiceParameter =: ParameterDice | ParameterList +ParameterDice =: Number|Range +ParameterList =: List +List=: OpenList String[Probability] [ListSeparator,String[Probability]]* CloseList +Probability=: OpenList (Range|Percentage) CloseList +Percentage =: number +Option =: Keep +| KeepAndExplode +| Filter +| Sort +| Count +| Reroll +| RerollUntil +| RerollAndAdd +| Explode +| Merge +| Bind +| Occurences +| Unique +| Paint +| If +| Split +| Group +Range =: OpenList Number RangeSeparator Number CloseList +RangeSeparator =: - ScalarOperator =: [x,-,*,x,/] -number =: [0-9]+ | constantValue -constantValue =: ${id | label} -id=[_,a-z][_,A-z,0-9]* -label=[_,a-z][_,A-z,0-9,é,è,ç,û,ê,â]* -variable = ${[0-9]+} -Validator =: BooleanValidator | RangeValidator | CompositeValidator -CompositeValidator =: Validator LogicOpetator Validator -LogicOpetator =: = | > | => | < | =< -RangeValidator =: [ number - number ] -BooleanValidator =: number | [operator number] | +number =: [-] [0-9]+ | constantValue +OpenVaribale=: ${ +CloseVariable=: } +constantValue =: OpenVaribale (id | label) CloseVariable +id=[_,a-z][_,A-z,0-9]* # must respect rules of QML id +label=.* +variable = OpenVaribale [0-9]+ CloseVariable +CompositeValidator =: OpenList Validator [LogicOpetator,Validator]* CloseList +LogicOpetator =: AND | XOR | OR +AND =: & +XOR =: ^ +OR =: | +Ascendant=:l +Validator =: BooleanValidator | RangeValidator | OperationValidator +CompareOpetator =: = | > | => | < | =< | != +RangeValidator =: Range +OperationValidator =: Modulo operandNode BooleanValidator +Modulo =: % +BooleanValidator =: [=]Operand | [CompareOpetator Operand] ListOfValue=: String[Range],ListOfValue | String[Range] -String =: [A-z0-9]+ -Keep =: k Number -KeepAndExplode =: K number -Reroll =: r -RerollUntil =: R -Exploding =: e -RerollOnceAndAdd =: a -RerollAndAdd =: A -Painter =: p -Split =: u -Group =: g +String =: .*[^ListSeparator] +Keep =: k[Ascendant] Number +KeepAndExplode =: K[Ascendant] number +Filter =: f CompositeValidator +Sort =: s[Ascendant] +Count =: c CompositeValidator +Reroll =: r CompositeValidator +RerollUntil =: R CompositeValidator +RerollAndAdd =: a CompositeValidator +Merge =: m +Bind =: b +Occurences =: OccurencesWidth ( ListSeparator number | CompositeValidator) +OccurencesWidth =: number +unique =: u +Painter =: p PainterParameters +PainterParameters =: OpenList PairColorOccurence [ListSeparator , PairColorOccurence]* CloseList +PairColorOccurence =: Color PairSeparator Number +PairSeparator =: : +If =: i [compareMethod] CompositeValidator Bloc[Bloc] +compareMethod =: OnEach | OneOfThem | AllOfThem | onScalar +OnEach =: '' +OneOfThem = '.' +AllOfThem = '*' +onScalar = ':' +Bloc =: OpenBranch Expression CloseBranch +OpenBloc =: { +CloseBloc =: } +Split =: y +Group =: g Number Sort =: s -If =: i compareMethod [Validator] {Expression}[{Expression}] -Paint =: p [ Count : color ] Group =: number -Explode =: e Validator -Jumpbackward =: @DiceOperation +Explode =: e CompositeValidator +NodeOperator = Jumpbackward +Jumpbackward =: @ Merge =: m | m Expression -Filter =: f Validator -Parenthese =: (expression) -Count =: c Validator +Command =: help | la +uniqueValue = u +Comment =: StartComment String +StartComment =: # ``` diff --git a/booleancondition.cpp b/booleancondition.cpp index f62c900..82d599b 100644 --- a/booleancondition.cpp +++ b/booleancondition.cpp @@ -20,7 +20,66 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "booleancondition.h" -#include <QDebug> + +Dice::CONDITION_STATE testEqual(bool insideRange, const std::pair<qint64, qint64>& range) +{ + if(!insideRange) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(insideRange && (range.first == range.second)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testGreatherThan(qint64 value, const std::pair<qint64, qint64>& range) +{ + if(value >= std::max(range.first, range.second)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(value < std::min(range.first, range.second)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testLesserThan(qint64 value, const std::pair<qint64, qint64>& range) +{ + if(value <= std::min(range.first, range.second)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(value > std::max(range.first, range.second)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testGreaterOrEqual(qint64 value, const std::pair<qint64, qint64>& range) +{ + if(value > std::max(range.first, range.second)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(value <= std::min(range.first, range.second)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testLesserOrEqual(qint64 value, const std::pair<qint64, qint64>& range) +{ + if(value < std::min(range.first, range.second)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(value >= std::max(range.first, range.second)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testDifferent(bool inside, const std::pair<qint64, qint64>& range) +{ + if(inside && (range.first == range.second)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(!inside) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} BooleanCondition::BooleanCondition() : m_operator(Equal) {} @@ -117,39 +176,41 @@ QString BooleanCondition::toString() } return QStringLiteral("[%1%2]").arg(str).arg(valueToScalar()); } -bool BooleanCondition::isValidRangeSize(std::pair<qint64, qint64> range) const + +Dice::CONDITION_STATE BooleanCondition::isValidRangeSize(const std::pair<qint64, qint64>& range) const { - bool isValid= false; + Dice::CONDITION_STATE state; auto valueScalar= valueToScalar(); qint64 boundValue= qBound(range.first, valueScalar, range.second); + bool isInsideRange= (boundValue == valueScalar); switch(m_operator) { case Equal: - isValid= (boundValue == valueScalar); + state= testEqual(isInsideRange, range); //(isInsideRange && (range.first != range.second)) ? ; break; case GreaterThan: - isValid= range.first <= valueScalar; + state= testGreatherThan(valueScalar, range); break; case LesserThan: - isValid= range.second >= valueScalar; + state= testLesserThan(valueScalar, range); break; case GreaterOrEqual: - isValid= range.first < valueScalar; + state= testGreaterOrEqual(valueScalar, range); break; case LesserOrEqual: - isValid= range.second > valueScalar; + state= testLesserOrEqual(valueScalar, range); break; case Different: - isValid= (boundValue == valueScalar); + state= testDifferent(isInsideRange, range); break; } - return isValid; + return state; } Validator* BooleanCondition::getCopy() const { BooleanCondition* val= new BooleanCondition(); val->setOperator(m_operator); - val->setValueNode(m_value); + val->setValueNode(m_value->getCopy()); return val; } qint64 BooleanCondition::valueToScalar() const @@ -159,5 +220,8 @@ qint64 BooleanCondition::valueToScalar() const m_value->run(nullptr); auto result= m_value->getResult(); - return result->getResult(Result::SCALAR).toInt(); + if(result) + return result->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); + else + return 0; } diff --git a/booleancondition.h b/booleancondition.h index c542a0c..54c243a 100644 --- a/booleancondition.h +++ b/booleancondition.h @@ -42,20 +42,20 @@ public: Different }; BooleanCondition(); - virtual ~BooleanCondition(); + virtual ~BooleanCondition() override; - virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const; + virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override; void setOperator(LogicOperator m); void setValueNode(ExecutionNode*); QString toString(); - virtual bool isValidRangeSize(std::pair<qint64, qint64> range) const; + virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override; /** * @brief getCopy * @return */ - virtual Validator* getCopy() const; + virtual Validator* getCopy() const override; private: qint64 valueToScalar() const; diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 215287d..c697899 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -3,15 +3,57 @@ cmake_minimum_required(VERSION 3.5) option(UPDATE_TRANSLATIONS "update Translation" 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/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. set(CMAKE_AUTOMOC ON) - set(EXECUTABLE_OUTPUT_PATH bin/) # Find the QtWidgets library @@ -38,7 +80,6 @@ set(dice_RESOURCES diceparser.qrc) find_package(Qt5LinguistTools) find_package(Qt5Svg) - IF(UPDATE_TRANSLATIONS) MESSAGE( update Translation ) FILE(GLOB_RECURSE translate_dice_SRCS ../*.cpp ../*.h) @@ -50,17 +91,8 @@ ELSE() ENDIF(UPDATE_TRANSLATIONS) if(Qt5Core_FOUND) - - #IF(UPDATE_TRANSLATIONS) - MESSAGE(status "find" ${dice_TS} ${translate_SRCS} ) - #QT5_CREATE_TRANSLATION(dice_QM ${translate_SRCS} ${dice_TS}) - #ELSE() - #QT5_ADD_TRANSLATION(dice_QM ${dice_TS}) - #ENDIF() - + MESSAGE(status "find" ${dice_TS} ${translate_SRCS} ) QT5_ADD_RESOURCES(dice_RESOURCES_RCC ${dice_RESOURCES}) - - # guess plugins and libraries directory set(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins") get_target_property(QT_LIBRARY_DIR Qt5::Core LOCATION) get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} PATH) @@ -73,7 +105,9 @@ SET( cli_sources set(documentation_files ../HelpMe.md ../README.md) -add_executable( dice ${cli_sources} ${dice_QM} ${documentation_files}) +add_executable( dice ${cli_sources} ${dice_QM} ${dice_sources} ${documentation_files}) +target_include_directories(dice PRIVATE ../include) + target_link_libraries(dice diceparser ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Svg_LIBRARIES}) INSTALL_TARGETS(/bin dice) diff --git a/cli/main.cpp b/cli/main.cpp index d6f6398..c597dea 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -35,6 +35,7 @@ #include <QCoreApplication> #endif +#include "dicealias.h" #include "diceparser.h" #include "displaytoolbox.h" #include "highlightdice.h" @@ -115,7 +116,7 @@ QString diceToMarkdown(QJsonArray array, bool withColor, bool allSameColor, bool } void displayJSon(QString scalarText, QString resultStr, QJsonArray array, bool withColor, QString cmd, QString error, - QString warning, QString comment, bool allSameFaceCount, bool allSameColor) + QString warning, QString comment, bool allSameFaceCount, bool allSameColor) { Q_UNUSED(withColor); QJsonDocument doc; @@ -133,7 +134,7 @@ void displayJSon(QString scalarText, QString resultStr, QJsonArray array, bool w out << doc.toJson() << "\n"; } void displayMarkdown(QString scalarText, QString resultStr, QJsonArray array, bool withColor, QString cmd, - QString error, QString warning, QString comment, bool allSameFaceCount, bool allSameColor) + QString error, QString warning, QString comment, bool allSameFaceCount, bool allSameColor) { Q_UNUSED(withColor); QString str("```Markdown\n"); @@ -165,7 +166,7 @@ void displayMarkdown(QString scalarText, QString resultStr, QJsonArray array, bo out << str; } QString displaySVG(QString scalarText, QString resultStr, QJsonArray array, bool withColor, QString cmd, QString error, - QString warning, QString comment, bool allSameFaceCount, bool allSameColor) + QString warning, QString comment, bool allSameFaceCount, bool allSameColor) { QString str( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" " @@ -222,16 +223,16 @@ QString displaySVG(QString scalarText, QString resultStr, QJsonArray array, bool #ifdef PAINTER_OP void displayImage(QString scalarText, QString resultStr, QJsonArray array, bool withColor, QString cmd, QString error, - QString warning, QString comment, bool allSameFaceCount, bool allSameColor) + QString warning, QString comment, bool allSameFaceCount, bool allSameColor) { - auto svg= displaySVG( - scalarText, resultStr, array, withColor, cmd, error, warning, comment, allSameFaceCount, allSameColor); + auto svg= displaySVG(scalarText, resultStr, array, withColor, cmd, error, warning, comment, allSameFaceCount, + allSameColor); out << DisplayToolBox::makeImage(svg.toUtf8()); } #endif void displayCommandResult(QString scalarText, QString resultStr, QJsonArray array, bool withColor, QString cmd, - QString error, QString warning, QString comment, bool allSameFaceCount, bool allSameColor) + QString error, QString warning, QString comment, bool allSameFaceCount, bool allSameColor) { // TODO display warning if(!error.isEmpty()) @@ -366,11 +367,6 @@ int startDiceParsing(QStringList& cmds, QString& treeFile, bool withColor, EXPOR stringResult.replace("\\n", "\n"); stringResult= ParsingToolBox::replaceVariableToValue(stringResult, strLst); - /*for(auto it= strLst.rbegin(); it != strLst.rend(); ++it) - { - stringResult.replace(QStringLiteral("$%1").arg(i), (*it)); - --i; - }*/ int i= strLst.size(); for(auto it= strLst.rbegin(); it != strLst.rend(); ++it) @@ -405,26 +401,26 @@ int startDiceParsing(QStringList& cmds, QString& treeFile, bool withColor, EXPOR { case TERMINAL: displayCommandResult(scalarText, resultStr, array, withColor, cmdRework, error, warnings, comment, - allSameFaceCount, allSameColor); + allSameFaceCount, allSameColor); break; case SVG: out << displaySVG(scalarText, resultStr, array, withColor, cmdRework, error, warnings, comment, - allSameFaceCount, allSameColor) + allSameFaceCount, allSameColor) << "\n"; break; case BOT: case MARKDOWN: displayMarkdown(scalarText, resultStr, array, withColor, cmdRework, error, warnings, comment, - allSameFaceCount, allSameColor); + allSameFaceCount, allSameColor); break; case JSON: displayJSon(scalarText, resultStr, array, withColor, cmdRework, error, warnings, comment, - allSameFaceCount, allSameColor); + allSameFaceCount, allSameColor); break; #ifdef PAINTER_OP case IMAGE: displayImage(scalarText, resultStr, array, withColor, cmdRework, error, warnings, comment, - allSameFaceCount, allSameColor); + allSameFaceCount, allSameColor); break; #endif } @@ -440,10 +436,12 @@ int startDiceParsing(QStringList& cmds, QString& treeFile, bool withColor, EXPOR } else { + QString error= parser.humanReadableError(); + err << "Error: " << error << "\n"; rt= 1; } } - + parser.cleanAll(); return rt; } #include <QTextCodec> @@ -466,38 +464,39 @@ int main(int argc, char* argv[]) QCommandLineParser optionParser; QCommandLineOption color(QStringList() << "c" << "color-off", - "Disable color to highlight result"); + "Disable color to highlight result"); QCommandLineOption version(QStringList() << "v" << "version", - "Show the version and quit."); + "Show the version and quit."); QCommandLineOption reset(QStringList() << "reset-settings", "Erase the settings and use the default parameters"); QCommandLineOption alias(QStringList() << "a" << "alias", - "path to alias json files: <aliasfile>", "aliasfile"); + "path to alias json files: <aliasfile>", "aliasfile"); QCommandLineOption character(QStringList() << "s" << "charactersheet", - "set Parameters to simulate character sheet: <sheetfile>", "sheetfile"); + "set Parameters to simulate character sheet: <sheetfile>", "sheetfile"); QCommandLineOption markdown(QStringList() << "m" << "markdown", - "The output is formatted in markdown."); + "The output is formatted in markdown."); QCommandLineOption bot(QStringList() << "b" << "bot", - "Discord bot."); + "Discord bot."); QCommandLineOption svg(QStringList() << "g" << "svg", - "The output is formatted in svg."); + "The output is formatted in svg."); QCommandLineOption json(QStringList() << "j" << "json", - "The output is formatted in json."); + "The output is formatted in json."); QCommandLineOption dotFile(QStringList() << "d" << "dot-file", - "Instead of rolling dice, generate the execution tree and write it in <dotfile>", "dotfile"); + "Instead of rolling dice, generate the execution tree and write it in <dotfile>", + "dotfile"); QCommandLineOption translation(QStringList() << "t" << "translation", - "path to the translation file: <translationfile>", "translationfile"); + "path to the translation file: <translationfile>", "translationfile"); QCommandLineOption help(QStringList() << "h" << "help", - "Display this help"); + "Display this help"); optionParser.addOption(color); optionParser.addOption(version); diff --git a/compositevalidator.cpp b/compositevalidator.cpp index 0715078..5116b16 100644 --- a/compositevalidator.cpp +++ b/compositevalidator.cpp @@ -21,22 +21,18 @@ ***************************************************************************/ #include "compositevalidator.h" -CompositeValidator::CompositeValidator() : m_operators(nullptr), m_validatorList(nullptr) {} +CompositeValidator::CompositeValidator() {} CompositeValidator::~CompositeValidator() { - qDeleteAll(*m_validatorList); - if(nullptr != m_operators) - { - delete m_operators; - } + qDeleteAll(m_validatorList); } qint64 CompositeValidator::hasValid(Die* b, bool recursive, bool unhighlight) const { int i= 0; qint64 sum= 0; bool highLight= false; - for(auto& validator : *m_validatorList) + for(auto& validator : m_validatorList) { qint64 val= validator->hasValid(b, recursive, unhighlight); if(i == 0) @@ -49,7 +45,7 @@ qint64 CompositeValidator::hasValid(Die* b, bool recursive, bool unhighlight) co } else { - switch(m_operators->at(i - 1)) + switch(m_operators.at(i - 1)) { case OR: sum|= val; @@ -99,41 +95,98 @@ QString CompositeValidator::toString() return QString("[%1%2]").arg(str).arg(m_value);*/ return str; } -bool CompositeValidator::isValidRangeSize(std::pair<qint64, qint64> range) const + +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) { - bool val= true; - int i= -1; - for(auto& tmp : *m_validatorList) + if(before == Dice::CONDITION_STATE::UNREACHABLE && current == Dice::CONDITION_STATE::UNREACHABLE) + return Dice::CONDITION_STATE::UNREACHABLE; + else if(before == Dice::CONDITION_STATE::ALWAYSTRUE || current == Dice::CONDITION_STATE::ALWAYSTRUE) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE testXOR(Dice::CONDITION_STATE before, Dice::CONDITION_STATE current) +{ + if(before == current + && (before == Dice::CONDITION_STATE::UNREACHABLE || before == Dice::CONDITION_STATE::ALWAYSTRUE)) + return Dice::CONDITION_STATE::UNREACHABLE; + else if((before != current) + && (before == Dice::CONDITION_STATE::ALWAYSTRUE || before == Dice::CONDITION_STATE::UNREACHABLE) + && (before != Dice::CONDITION_STATE::REACHABLE || current != Dice::CONDITION_STATE::REACHABLE)) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else + return Dice::CONDITION_STATE::REACHABLE; +} + +Dice::CONDITION_STATE CompositeValidator::isValidRangeSize(const std::pair<qint64, qint64>& range) const +{ + std::vector<Dice::CONDITION_STATE> vec; + std::transform( + m_validatorList.begin(), m_validatorList.end(), std::back_inserter(vec), + [range](Validator* validator) -> Dice::CONDITION_STATE { return validator->isValidRangeSize(range); }); + + auto itError= std::find(vec.begin(), vec.end(), Dice::CONDITION_STATE::ERROR); + + if((static_cast<int>(vec.size()) != m_operators.size() + 1) || (itError != vec.end())) { - bool rel= tmp->isValidRangeSize(range); - val|= rel; - ++i; + return Dice::CONDITION_STATE::ERROR; } + std::size_t i= 0; + Dice::CONDITION_STATE val; + 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; + break; + } + + ++i; + } return val; } -void CompositeValidator::setOperationList(QVector<LogicOperation>* m) + +void CompositeValidator::setOperationList(const QVector<LogicOperation>& m) { m_operators= m; } -void CompositeValidator::setValidatorList(QList<Validator*>* m) +void CompositeValidator::setValidatorList(const QList<Validator*>& valids) { - m_validatorList= m; + qDeleteAll(m_validatorList); + m_validatorList= valids; } Validator* CompositeValidator::getCopy() const { - QVector<LogicOperation>* vector= new QVector<LogicOperation>(); - *vector= *m_operators; - - QList<Validator*>* list= new QList<Validator*>(); - for(auto& val : *m_validatorList) - { - list->append(val->getCopy()); - } - CompositeValidator* val= new CompositeValidator(); - val->setOperationList(vector); - val->setValidatorList(list); + val->setOperationList(m_operators); + val->setValidatorList(m_validatorList); return val; } diff --git a/compositevalidator.h b/compositevalidator.h index c49355d..2d7479d 100644 --- a/compositevalidator.h +++ b/compositevalidator.h @@ -43,22 +43,22 @@ public: NONE }; CompositeValidator(); - virtual ~CompositeValidator(); + virtual ~CompositeValidator() override; - virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const; + virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override; - void setOperationList(QVector<LogicOperation>* m); - void setValidatorList(QList<Validator*>*); + void setOperationList(const QVector<LogicOperation>& m); + void setValidatorList(const QList<Validator*>& valids); - QString toString(); + QString toString() override; - virtual bool isValidRangeSize(std::pair<qint64, qint64> range) const; + virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override; - virtual Validator* getCopy() const; + virtual Validator* getCopy() const override; private: - QVector<LogicOperation>* m_operators; - QList<Validator*>* m_validatorList; + QVector<LogicOperation> m_operators; + QList<Validator*> m_validatorList; }; #endif // BOOLEANCONDITION_H diff --git a/diceparser.cpp b/diceparser.cpp index 4ec44ef..ea8f251 100644 --- a/diceparser.cpp +++ b/diceparser.cpp @@ -29,6 +29,7 @@ #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" @@ -164,11 +165,7 @@ bool DiceParser::parseLine(QString str, bool allowAlias) { m_errorMap.clear(); m_comment= QString(""); - if(!m_startNodes.empty()) - { - qDeleteAll(m_startNodes); - m_startNodes.clear(); - } + cleanAll(); m_currentTreeHasSeparator= false; if(allowAlias) { @@ -180,7 +177,7 @@ bool DiceParser::parseLine(QString str, bool allowAlias) if(!hasInstruction) { m_errorMap.insert( - ExecutionNode::NOTHING_UNDERSTOOD, + 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/" @@ -190,7 +187,7 @@ bool DiceParser::parseLine(QString str, bool allowAlias) { auto i= m_command.size() - str.size(); m_warningMap.insert( - ExecutionNode::UNEXPECTED_CHARACTER, + 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()) @@ -226,7 +223,7 @@ bool DiceParser::readExpression(QString& str, ExecutionNode*& node) } else { - m_warningMap.insert(ExecutionNode::BAD_SYNTAXE, + m_warningMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE, QObject::tr("Expected closing parenthesis - can't validate the inside.")); } } @@ -373,6 +370,15 @@ bool DiceParser::readNode(QString& str, ExecutionNode*& node) return false; } +void DiceParser::cleanAll() +{ + if(!m_startNodes.empty()) + { + qDeleteAll(m_startNodes); + m_startNodes.clear(); + } +} + void DiceParser::start() { for(auto start : m_startNodes) @@ -392,11 +398,11 @@ QList<qreal> DiceParser::getLastIntegerResults() bool scalarDone= false; while((result != nullptr) && (!scalarDone)) { - if(result->hasResultOfType(Result::SCALAR)) + if(result->hasResultOfType(Dice::RESULT_TYPE::SCALAR)) { if(!alreadyVisitedNode.contains(result->getId())) { - resultValues << result->getResult(Result::SCALAR).toReal(); + resultValues << result->getResult(Dice::RESULT_TYPE::SCALAR).toReal(); alreadyVisitedNode << result->getId(); } scalarDone= true; @@ -417,9 +423,9 @@ QStringList DiceParser::getStringResult() bool found= false; while((nullptr != result) && (!found)) { - if(result->hasResultOfType(Result::STRING)) + if(result->hasResultOfType(Dice::RESULT_TYPE::STRING)) { - str= result->getResult(Result::STRING).toString(); + str= result->getResult(Dice::RESULT_TYPE::STRING).toString(); found= true; } result= result->getPrevious(); @@ -440,7 +446,7 @@ QStringList DiceParser::getAllStringResult(bool& hasAlias) while(nullptr != result) { - if(result->hasResultOfType(Result::STRING)) + if(result->hasResultOfType(Dice::RESULT_TYPE::STRING)) { StringResult* stringResult= dynamic_cast<StringResult*>(result); if(nullptr != stringResult) @@ -465,7 +471,7 @@ QStringList DiceParser::getAllDiceResult(bool& hasAlias) while(nullptr != result) { - if(result->hasResultOfType(Result::DICE_LIST)) + if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) { DiceResult* stringResult= dynamic_cast<DiceResult*>(result); if(nullptr != stringResult) @@ -508,7 +514,7 @@ void DiceParser::getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resu ExportedDiceResult nodeResult; while(nullptr != result) { - if(result->hasResultOfType(Result::DICE_LIST)) + if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) { DiceResult* diceResult= dynamic_cast<DiceResult*>(result); QList<HighLightDice> list; @@ -540,7 +546,7 @@ void DiceParser::getLastDiceResult(QList<ExportedDiceResult>& diceValuesList, bo Result* result= next->getResult(); while(nullptr != result) { - if(result->hasResultOfType(Result::DICE_LIST)) + if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) { DiceResult* diceResult= dynamic_cast<DiceResult*>(result); if(nullptr != diceResult) @@ -604,7 +610,7 @@ bool DiceParser::hasIntegerResultNotInFirst() bool result= false; for(auto node : m_startNodes) { - result|= hasResultOfType(Result::SCALAR, node); + result|= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node); } return result; } @@ -614,7 +620,7 @@ bool DiceParser::hasDiceResult() bool result= false; for(auto node : m_startNodes) { - result|= hasResultOfType(Result::DICE_LIST, node); + result|= hasResultOfType(Dice::RESULT_TYPE::DICE_LIST, node); } return result; } @@ -623,18 +629,22 @@ bool DiceParser::hasStringResult() bool result= false; for(auto node : m_startNodes) { - result|= hasResultOfType(Result::STRING, node); + result|= hasResultOfType(Dice::RESULT_TYPE::STRING, node); } return result; } -bool DiceParser::hasResultOfType(Result::RESULT_TYPE type, ExecutionNode* node, bool notthelast) +bool DiceParser::hasResultOfType(Dice::RESULT_TYPE type, ExecutionNode* node, bool notthelast) { bool scalarDone= false; ExecutionNode* next= getLeafNode(node); Result* result= next->getResult(); while((result != nullptr) && (!scalarDone)) { - if(result->hasResultOfType(type) && ((!notthelast) || (nullptr != result->getPrevious()))) + bool lastResult= false; + if(notthelast) + lastResult= (nullptr != result->getPrevious()); + + if(result->hasResultOfType(type) && !lastResult) { scalarDone= true; } @@ -653,7 +663,7 @@ QList<qreal> DiceParser::getSumOfDiceResult() bool found= false; while((nullptr != result) && (!found)) { - if(result->hasResultOfType(Result::DICE_LIST)) + if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST)) { DiceResult* myDiceResult= dynamic_cast<DiceResult*>(result); if(nullptr != myDiceResult) @@ -704,7 +714,7 @@ bool DiceParser::readDice(QString& str, ExecutionNode*& node) if(max < 1) { m_errorMap.insert( - ExecutionNode::BAD_SYNTAXE, + 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; } @@ -759,7 +769,7 @@ bool DiceParser::readDice(QString& str, ExecutionNode*& node) else { m_errorMap.insert( - ExecutionNode::BAD_SYNTAXE, + Dice::ERROR_CODE::BAD_SYNTAXE, QObject::tr( "List is missing after the L operator. Please, add it (e.g : 1L[sword,spear,gun,arrow])")); } @@ -1087,7 +1097,7 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, } else { - m_errorMap.insert(ExecutionNode::BAD_SYNTAXE, + m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE, QObject::tr("Validator is missing after the c operator. Please, change it")); } } @@ -1098,14 +1108,33 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, // 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) { - if(!m_parsingToolbox->isValidValidator(previous, validator)) + switch(m_parsingToolbox->isValidValidator(previous, validator)) { - m_errorMap.insert( - ExecutionNode::BAD_SYNTAXE, - QObject::tr("Validator is missing after the %1 operator. Please, change it") - .arg(operatorName == Reroll ? "r" : "a")); + case Dice::CONDITION_STATE::ALWAYSTRUE: + if(operatorName == RerollAndAdd) + { + m_errorMap.insert( + Dice::ERROR_CODE::ENDLESS_LOOP_ERROR, + QObject::tr( + "Validator is always true missing after 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("Candition can be reached, causing endless loop. Please, " + "change the %1 option condition") + .arg(symbol)); + } + break; + case Dice::CONDITION_STATE::ERROR: + default: + break; } auto reroll= (operatorName == RerollAndAdd || operatorName == Reroll); @@ -1123,13 +1152,9 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, } else { - m_errorMap.insert(ExecutionNode::BAD_SYNTAXE, - QObject::tr("Validator is missing after the %1 operator. Please, change it") - .arg(operatorName == Reroll ? - QStringLiteral("r") : - operatorName == RerollUntil ? - QStringLiteral("R") : - operatorName == RerollAndAdd ? QStringLiteral("a") : "")); + m_errorMap.insert( + Dice::ERROR_CODE::BAD_SYNTAXE, + QObject::tr("Validator is missing after the %1 operator. Please, change it").arg(symbol)); } } break; @@ -1138,9 +1163,9 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, Validator* validator= m_parsingToolbox->readCompositeValidator(str); if(nullptr != validator) { - if(!m_parsingToolbox->isValidValidator(previous, validator)) + if(Dice::CONDITION_STATE::ALWAYSTRUE == m_parsingToolbox->isValidValidator(previous, validator)) { - m_errorMap.insert(ExecutionNode::ENDLESS_LOOP_ERROR, + m_errorMap.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR, QObject::tr("This condition %1 introduces an endless loop. Please, change it") .arg(validator->toString())); } @@ -1152,7 +1177,7 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, } else { - m_errorMap.insert(ExecutionNode::BAD_SYNTAXE, + m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE, QObject::tr("Validator is missing after the e operator. Please, change it")); } } @@ -1210,10 +1235,18 @@ bool DiceParser::readOption(QString& str, ExecutionNode* previous) //, case Painter: { PainterNode* painter= new PainterNode(); - m_parsingToolbox->readPainterParameter(painter, str); - previous->setNextNode(painter); - node= painter; - found= true; + 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: @@ -1345,9 +1378,9 @@ void DiceParser::setComment(const QString& comment) m_comment= comment; } -QMap<ExecutionNode::DICE_ERROR_CODE, QString> DiceParser::getErrorMap() +QMap<Dice::ERROR_CODE, QString> DiceParser::getErrorMap() { - QMap<ExecutionNode::DICE_ERROR_CODE, QString> map; + QMap<Dice::ERROR_CODE, QString> map; for(auto start : m_startNodes) { @@ -1362,7 +1395,7 @@ QMap<ExecutionNode::DICE_ERROR_CODE, QString> DiceParser::getErrorMap() } QString DiceParser::humanReadableError() { - QMapIterator<ExecutionNode::DICE_ERROR_CODE, QString> i(m_errorMap); + QMapIterator<Dice::ERROR_CODE, QString> i(m_errorMap); QString str(""); while(i.hasNext()) { @@ -1372,7 +1405,7 @@ QString DiceParser::humanReadableError() } /// list - QMapIterator<ExecutionNode::DICE_ERROR_CODE, QString> j(getErrorMap()); + QMapIterator<Dice::ERROR_CODE, QString> j(getErrorMap()); while(j.hasNext()) { j.next(); @@ -1384,7 +1417,7 @@ QString DiceParser::humanReadableError() QString DiceParser::humanReadableWarning() { - QMapIterator<ExecutionNode::DICE_ERROR_CODE, QString> i(m_warningMap); + QMapIterator<Dice::ERROR_CODE, QString> i(m_warningMap); QString str(""); while(i.hasNext()) { diff --git a/diceparser.pc.in b/diceparser.pc.in new file mode 100644 index 0000000..61b5aea --- /dev/null +++ b/diceparser.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ + +Requires: +Libs: -L${libdir} -ldiceparser +Cflags: -I${includedir} @@ -35,7 +35,7 @@ Die::Die() , m_op(Die::PLUS) //,m_mt(m_randomDevice) { auto seed= std::chrono::high_resolution_clock::now().time_since_epoch().count(); - m_rng= std::mt19937(quintptr(this) + seed); + m_rng= std::mt19937(quintptr(this) + static_cast<unsigned long long>(seed)); } Die::Die(const Die& die) { @@ -49,6 +49,8 @@ Die::Die(const Die& die) m_base= die.m_base; m_color= die.getColor(); m_op= die.getOp(); + auto seed= std::chrono::high_resolution_clock::now().time_since_epoch().count(); + m_rng= std::mt19937(quintptr(this) + static_cast<unsigned long long>(seed)); } void Die::setValue(qint64 r) @@ -151,8 +151,8 @@ private: bool m_hasValue= false; bool m_displayStatus= false; bool m_highlighted= true; - qint64 m_maxValue; - qint64 m_base; + qint64 m_maxValue= 0; + qint64 m_base= 0; QString m_color; Die::ArithmeticOperator m_op; diff --git a/highlightdice.cpp b/highlightdice.cpp index 02941d5..c2abdb6 100644 --- a/highlightdice.cpp +++ b/highlightdice.cpp @@ -17,7 +17,7 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "highlightdice.h" +#include "include/highlightdice.h" HighLightDice::HighLightDice(QList<qint64> result, bool isHighlighted, QString color, bool displayed, quint64 faces) : m_result(result), m_hasHighlight(isHighlighted), m_color(color), m_displayed(displayed), m_faces(faces) diff --git a/dicealias.h b/include/dicealias.h index 463a654..463a654 100644 --- a/dicealias.h +++ b/include/dicealias.h diff --git a/diceparser.h b/include/diceparser.h index 8ecfb50..32694a3 100644 --- a/diceparser.h +++ b/include/diceparser.h @@ -24,10 +24,11 @@ #include <QMap> #include <QString> +#include <vector> -#include "dicealias.h" #include "highlightdice.h" -#include "node/executionnode.h" +#include "diceparserhelper.h" +//#include "node/executionnode.h" typedef QList<HighLightDice> ListDiceResult; typedef QMap<quint64, ListDiceResult> ExportedDiceResult; @@ -35,6 +36,8 @@ typedef QMap<quint64, ListDiceResult> ExportedDiceResult; class ExplodeDiceNode; class ParsingToolBox; class DiceRollerNode; +class DiceAlias; +class ExecutionNode; /** * @page DiceParser Dice Parser * @@ -123,18 +126,6 @@ public: * */ void start(); - - /** - * @brief displayResult - */ - QString displayResult(); - /** - * @brief readExpression - * @param str - * @param node - * @return - */ - bool readExpression(QString& str, ExecutionNode*& node); /** * @brief displayDotTree - Write the execution tree into file using dot format. * @param filepath absolute or relative path to the tree file. @@ -204,7 +195,7 @@ public: * @brief getErrorList * @return */ - QMap<ExecutionNode::DICE_ERROR_CODE, QString> getErrorMap(); + QMap<Dice::ERROR_CODE, QString> getErrorMap(); /** * @brief setPathToHelp set the path to the documentation, this path must be adatped to the lang of application etc… * @param l the path. @@ -226,15 +217,7 @@ public: * @return true when the command has separator, false otherwise. */ bool hasSeparator() const; - /** - * @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); + /** * @brief setVariableDictionary * @param variables @@ -243,20 +226,33 @@ public: QString getComment() const; void setComment(const QString& comment); - bool readOptionFromNull(QString& str, ExecutionNode*& node); - bool readOperatorFromNull(QString& str, ExecutionNode*& node); - - bool readInstructionList(QString& str); void getDiceResultFromAllInstruction(QList<ExportedDiceResult>& resultList); QString humanReadableWarning(); bool readValuesList(QString& str, ExecutionNode*& node); - -protected: - bool readParameterNode(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 @@ -336,7 +332,8 @@ private: * @param notthelast * @return */ - bool hasResultOfType(Result::RESULT_TYPE, ExecutionNode* node, bool notthelast= false); + bool hasResultOfType(Dice::RESULT_TYPE, ExecutionNode* node, bool notthelast= false); + bool readBlocInstruction(QString& str, ExecutionNode*& resultnode); private: QMap<QString, DiceOperator>* m_mapDiceOp; @@ -345,17 +342,15 @@ private: QList<DiceAlias*>* m_aliasList; QStringList* m_commandList; - QMap<ExecutionNode::DICE_ERROR_CODE, QString> m_errorMap; - QMap<ExecutionNode::DICE_ERROR_CODE, QString> m_warningMap; + QMap<Dice::ERROR_CODE, QString> m_errorMap; + QMap<Dice::ERROR_CODE, QString> m_warningMap; ExecutionNode* m_start= nullptr; std::vector<ExecutionNode*> m_startNodes; - // ExecutionNode* m_current; QString m_command; ParsingToolBox* m_parsingToolbox; QString m_helpPath; bool m_currentTreeHasSeparator; - bool readBlocInstruction(QString& str, ExecutionNode*& resultnode); QString m_comment; }; diff --git a/include/diceparserhelper.h b/include/diceparserhelper.h new file mode 100644 index 0000000..00b9362 --- /dev/null +++ b/include/diceparserhelper.h @@ -0,0 +1,43 @@ +#ifndef DICEPARSERHELPER_H +#define DICEPARSERHELPER_H + +namespace Dice +{ + +enum class CONDITION_STATE : int +{ + ERROR, + ALWAYSTRUE, + UNREACHABLE, + REACHABLE +}; + +enum class ERROR_CODE : int +{ + NO_DICE_ERROR, + DIE_RESULT_EXPECTED, + BAD_SYNTAXE, + ENDLESS_LOOP_ERROR, + DIVIDE_BY_ZERO, + NOTHING_UNDERSTOOD, + NO_DICE_TO_ROLL, + TOO_MANY_DICE, + NO_VARIBALE, + INVALID_INDEX, + UNEXPECTED_CHARACTER, + NO_PREVIOUS_ERROR, + NO_VALID_RESULT +}; + +/** + * @brief The RESULT_TYPE enum or combinaison + */ +enum class RESULT_TYPE : int +{ + NONE= 0, + SCALAR= 1, + STRING= 2, + DICE_LIST= 4 +}; +} +#endif // DICEPARSERHELPER_H diff --git a/highlightdice.h b/include/highlightdice.h index 2e8f08a..2e8f08a 100644 --- a/highlightdice.h +++ b/include/highlightdice.h diff --git a/parsingtoolbox.h b/include/parsingtoolbox.h index b91db1a..8d5f62b 100644 --- a/parsingtoolbox.h +++ b/include/parsingtoolbox.h @@ -175,7 +175,7 @@ public: * @param val * @return */ - bool isValidValidator(ExecutionNode* previous, Validator* val); + Dice::CONDITION_STATE isValidValidator(ExecutionNode* previous, Validator* val); /** * @brief getDiceRollerNode * @param previous @@ -206,7 +206,7 @@ public: bool readArithmeticOperator(QString& str, Die::ArithmeticOperator& op); - static void readPainterParameter(PainterNode* painter, QString& str); + static bool readPainterParameter(PainterNode* painter, QString& str); static QHash<QString, QString> getVariableHash(); static void setVariableHash(const QHash<QString, QString>& variableHash); diff --git a/node/countexecutenode.cpp b/node/countexecutenode.cpp index bc8e3b3..763a320 100644 --- a/node/countexecutenode.cpp +++ b/node/countexecutenode.cpp @@ -34,7 +34,7 @@ void CountExecuteNode::run(ExecutionNode* previous) { if(nullptr != m_validator) { - sum+= m_validator->hasValid(dice, true, true); + sum+= m_validator->hasValid(dice, true, true) ? 1 : 0; } } m_scalarResult->setValue(sum); diff --git a/node/dicerollernode.cpp b/node/dicerollernode.cpp index f57d3e3..f87908f 100644 --- a/node/dicerollernode.cpp +++ b/node/dicerollernode.cpp @@ -19,10 +19,10 @@ void DiceRollerNode::run(ExecutionNode* previous) Result* result= previous->getResult(); if(nullptr != result) { - auto num= result->getResult(Result::SCALAR).toReal(); + auto num= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal(); if(num <= 0) { - m_errors.insert(NO_DICE_TO_ROLL, QObject::tr("No dice to roll")); + m_errors.insert(Dice::ERROR_CODE::NO_DICE_TO_ROLL, QObject::tr("No dice to roll")); } m_diceCount= num > 0 ? static_cast<quint64>(num) : 0; m_result->setPrevious(result); @@ -30,7 +30,7 @@ void DiceRollerNode::run(ExecutionNode* previous) auto possibleValue= static_cast<quint64>(std::abs((m_max - m_min) + 1)); if(possibleValue < m_diceCount && m_unique) { - m_errors.insert(TOO_MANY_DICE, + m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE, QObject::tr("More unique values asked than possible values (D operator)")); return; } @@ -62,7 +62,7 @@ void DiceRollerNode::run(ExecutionNode* previous) quint64 DiceRollerNode::getFaces() const { - return std::abs(m_max - m_min) + 1; + return static_cast<quint64>(std::abs(m_max - m_min) + 1); } std::pair<qint64, qint64> DiceRollerNode::getRange() const diff --git a/node/executionnode.cpp b/node/executionnode.cpp index 5bee091..4545934 100644 --- a/node/executionnode.cpp +++ b/node/executionnode.cpp @@ -6,7 +6,7 @@ ExecutionNode::ExecutionNode() : m_previousNode(nullptr) , m_result(nullptr) , m_nextNode(nullptr) - , m_errors(QMap<ExecutionNode::DICE_ERROR_CODE, QString>()) + , m_errors(QMap<Dice::ERROR_CODE, QString>()) , m_id(QString("\"%1\"").arg(QUuid::createUuid().toString())) { } @@ -40,7 +40,7 @@ ExecutionNode* ExecutionNode::getNextNode() { return m_nextNode; } -QMap<ExecutionNode::DICE_ERROR_CODE, QString> ExecutionNode::getExecutionErrorMap() +QMap<Dice::ERROR_CODE, QString> ExecutionNode::getExecutionErrorMap() { if(nullptr != m_nextNode) { @@ -97,5 +97,5 @@ qint64 ExecutionNode::getScalarResult() { if(m_result == nullptr) return 0; - return m_result->getResult(Result::SCALAR).toInt(); + return m_result->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); } diff --git a/node/executionnode.h b/node/executionnode.h index e8eca1f..6321c83 100644 --- a/node/executionnode.h +++ b/node/executionnode.h @@ -1,8 +1,8 @@ #ifndef EXECUTIONNODE_H #define EXECUTIONNODE_H +#include "diceparserhelper.h" #include "result/result.h" -#include <QDebug> /** * @brief The ExecutionNode class @@ -10,21 +10,6 @@ class ExecutionNode { public: - enum DICE_ERROR_CODE - { - NO_DICE_ERROR, - DIE_RESULT_EXPECTED, - BAD_SYNTAXE, - ENDLESS_LOOP_ERROR, - DIVIDE_BY_ZERO, - NOTHING_UNDERSTOOD, - NO_DICE_TO_ROLL, - TOO_MANY_DICE, - NO_VARIBALE, - INVALID_INDEX, - UNEXPECTED_CHARACTER, - NO_PREVIOUS_ERROR - }; /** * @brief ExecutionNode */ @@ -72,7 +57,7 @@ public: * @brief getErrorList * @return */ - virtual QMap<ExecutionNode::DICE_ERROR_CODE, QString> getExecutionErrorMap(); + virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap(); /** * @brief generateDotTree @@ -101,7 +86,7 @@ protected: /** * @brief m_result */ - Result* m_result; + Result* m_result= nullptr; /** * @brief m_nextNode */ @@ -109,7 +94,7 @@ protected: /** * @brief m_errors */ - QMap<ExecutionNode::DICE_ERROR_CODE, QString> m_errors; + QMap<Dice::ERROR_CODE, QString> m_errors; QString m_id; }; diff --git a/node/explodedicenode.cpp b/node/explodedicenode.cpp index 704ac8a..2292a05 100644 --- a/node/explodedicenode.cpp +++ b/node/explodedicenode.cpp @@ -16,7 +16,6 @@ void ExplodeDiceNode::run(ExecutionNode* previous) for(auto& die : previous_result->getResultList()) { Die* tmpdie= new Die(*die); -// *tmpdie= *die; m_diceResult->insertResult(tmpdie); die->displayed(); } @@ -25,12 +24,23 @@ void ExplodeDiceNode::run(ExecutionNode* previous) for(auto& die : list) { + if(Dice::CONDITION_STATE::ALWAYSTRUE + == m_validator->isValidRangeSize(std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue()))) + { + m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR, + QObject::tr("Condition (%1) cause an endless loop with this dice: %2") + .arg(toString(true)) + .arg(QStringLiteral("d[%1,%2]") + .arg(static_cast<int>(die->getBase())) + .arg(static_cast<int>(die->getMaxValue())))); + continue; + } + while(m_validator->hasValid(die, false)) { die->roll(true); } } - // m_diceResult->setResultList(list); if(nullptr != m_nextNode) { diff --git a/node/forloopnode.cpp b/node/forloopnode.cpp index f65a389..aba6ff4 100644 --- a/node/forloopnode.cpp +++ b/node/forloopnode.cpp @@ -58,7 +58,7 @@ void ForLoopNode::run(ExecutionNode* previous) tmp= tmp->getNextNode(); } Result* internalResult= tmp->getResult(); - auto value= internalResult->getResult(Result::SCALAR).toInt(); + auto value= internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); Die* neodie= new Die(); *neodie= *dice; diff --git a/node/ifnode.cpp b/node/ifnode.cpp index 5470e15..f0f28aa 100644 --- a/node/ifnode.cpp +++ b/node/ifnode.cpp @@ -41,11 +41,11 @@ void IfNode::run(ExecutionNode* previous) ExecutionNode* nextNode= nullptr; bool runNext= (nullptr == m_nextNode) ? false : true; Result* previousResult= previous->getResult(); - m_result= previousResult; + m_result= previousResult->getCopy(); if(nullptr != m_result) { - qreal value= previousResult->getResult(Result::SCALAR).toReal(); + qreal value= previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(); if(nullptr != m_validator) { diff --git a/node/jumpbackwardnode.cpp b/node/jumpbackwardnode.cpp index 15c7063..2870854 100644 --- a/node/jumpbackwardnode.cpp +++ b/node/jumpbackwardnode.cpp @@ -96,7 +96,7 @@ void JumpBackwardNode::run(ExecutionNode* previous) if(nullptr != result) { //--i; - if(/*(i==0)&&*/ (result->hasResultOfType(Result::DICE_LIST))) + if(/*(i==0)&&*/ (result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))) { found= true; m_backwardNode= parent; @@ -118,7 +118,8 @@ void JumpBackwardNode::run(ExecutionNode* previous) } if(nullptr == result) { - m_errors.insert(DIE_RESULT_EXPECTED, + m_errors.insert( + Dice::ERROR_CODE::DIE_RESULT_EXPECTED, QObject::tr(" The @ operator expects dice result. Please check the documentation to fix your command.")); } else diff --git a/node/keepdiceexecnode.cpp b/node/keepdiceexecnode.cpp index 42b4c40..688c27b 100644 --- a/node/keepdiceexecnode.cpp +++ b/node/keepdiceexecnode.cpp @@ -58,9 +58,10 @@ void KeepDiceExecNode::run(ExecutionNode* previous) if(m_numberOfDice > static_cast<qint64>(diceList.size())) { - m_errors.insert(TOO_MANY_DICE, QObject::tr(" You ask to keep %1 dice but the result only has %2") - .arg(m_numberOfDice) - .arg(diceList.size())); + m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE, + QObject::tr(" You ask to keep %1 dice but the result only has %2") + .arg(m_numberOfDice) + .arg(diceList.size())); } for(auto& tmp : diceList.mid(static_cast<int>(m_numberOfDice), -1)) diff --git a/node/listsetrollnode.cpp b/node/listsetrollnode.cpp index ffa0f03..565a609 100644 --- a/node/listsetrollnode.cpp +++ b/node/listsetrollnode.cpp @@ -62,11 +62,11 @@ void ListSetRollNode::run(ExecutionNode* previous) Result* result= previous->getResult(); if(nullptr != result) { - quint64 diceCount= result->getResult(Result::SCALAR).toReal(); + quint64 diceCount= result->getResult(Dice::RESULT_TYPE::SCALAR).toReal(); if(diceCount > static_cast<quint64>(m_values.size()) && m_unique) { - m_errors.insert( - TOO_MANY_DICE, QObject::tr("More unique values asked than possible values (L operator)")); + m_errors.insert(Dice::ERROR_CODE::TOO_MANY_DICE, + QObject::tr("More unique values asked than possible values (L operator)")); } else { diff --git a/node/mergenode.cpp b/node/mergenode.cpp index 4a11a76..15f2fa7 100644 --- a/node/mergenode.cpp +++ b/node/mergenode.cpp @@ -29,7 +29,7 @@ void MergeNode::run(ExecutionNode* previous) { if(nullptr == previous) { - m_errors.insert(ExecutionNode::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Merge operator")); + m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Merge operator")); return; } @@ -40,46 +40,46 @@ 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; + + startResult->setPrevious(previousLast->getResult()); + previousLast->setNextNode(start); + + previousLast= last; + Result* tmpResult= last->getResult(); + while(nullptr != tmpResult) { - if(nullptr != previousLast) + DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult); + if(nullptr == dice) { - auto startResult= start->getResult(); - startResult->setPrevious(previousLast->getResult()); - previousLast->setNextNode(start); - } - previousLast= last; - Result* tmpResult= last->getResult(); - while(nullptr != tmpResult) - { - DiceResult* dice= dynamic_cast<DiceResult*>(tmpResult); - if(nullptr != dice) + ///@todo TODO improve here to set homogeneous while is really + m_diceResult->setHomogeneous(false); + for(auto& die : dice->getResultList()) { - ///@todo TODO improve here to set homogeneous while is really - m_diceResult->setHomogeneous(false); - for(auto& die : dice->getResultList()) + if(!m_diceResult->getResultList().contains(die) && (!die->hasBeenDisplayed())) { - if(!m_diceResult->getResultList().contains(die) && (!die->hasBeenDisplayed())) - { - Die* tmpdie= new Die(*die); - //*tmpdie= *die; - die->displayed(); - m_diceResult->getResultList().append(tmpdie); - } + Die* tmpdie= new Die(*die); + die->displayed(); + m_diceResult->getResultList().append(tmpdie); } } - auto it= std::find_if(pastResult.begin(), pastResult.end(), - [tmpResult](const Result* a) { return (a == tmpResult->getPrevious()); }); - if(it == pastResult.end()) - { - pastResult.push_back(previousLast->getResult()); - tmpResult= tmpResult->getPrevious(); - } - else - { - tmpResult->setPrevious(nullptr); - tmpResult= nullptr; - } + } + auto it= std::find_if(pastResult.begin(), pastResult.end(), + [tmpResult](const Result* a) { return (a == tmpResult->getPrevious()); }); + if(it == pastResult.end()) + { + pastResult.push_back(previousLast->getResult()); + tmpResult= tmpResult->getPrevious(); + } + else + { + tmpResult->setPrevious(nullptr); + tmpResult= nullptr; } } } diff --git a/node/occurencecountnode.cpp b/node/occurencecountnode.cpp index e0117ef..0d69d2a 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 <QVector> OccurenceCountNode::OccurenceCountNode() : ExecutionNode() {} diff --git a/node/paintnode.cpp b/node/paintnode.cpp index 02c7230..0cd4e10 100644 --- a/node/paintnode.cpp +++ b/node/paintnode.cpp @@ -47,7 +47,6 @@ void ColorItem::setColor(const QString& color) PainterNode::PainterNode() : ExecutionNode() { - m_result= nullptr; m_nextNode= nullptr; } @@ -61,15 +60,17 @@ void PainterNode::run(ExecutionNode* previous) m_previousNode= previous; if(nullptr == previous) { - m_errors.insert(ExecutionNode::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Paint operator")); + m_errors.insert(Dice::ERROR_CODE::NO_PREVIOUS_ERROR, QObject::tr("No previous node before Paint operator")); return; } Result* previousResult= previous->getResult(); - // m_result = previousResult; - DiceResult* previousDiceResult= dynamic_cast<DiceResult*>(previousResult); - if(nullptr != previousDiceResult) + if(nullptr == previousResult) + return; + + m_diceResult= dynamic_cast<DiceResult*>(previousResult->getCopy()); + if(nullptr != m_diceResult) { - QList<Die*> diceList= previousDiceResult->getResultList(); + QList<Die*> diceList= m_diceResult->getResultList(); int pastDice= 0; for(ColorItem& item : m_colors) { @@ -90,7 +91,7 @@ void PainterNode::run(ExecutionNode* previous) } Result* PainterNode::getResult() { - return (nullptr != m_previousNode) ? m_previousNode->getResult() : nullptr; + return m_diceResult; } QString PainterNode::toString(bool wl) const diff --git a/node/paintnode.h b/node/paintnode.h index 2675285..2283f83 100644 --- a/node/paintnode.h +++ b/node/paintnode.h @@ -55,6 +55,7 @@ public: protected: QList<ColorItem> m_colors; + DiceResult* m_diceResult= nullptr; }; #endif diff --git a/node/rerolldicenode.cpp b/node/rerolldicenode.cpp index 56ee6d9..70475a5 100644 --- a/node/rerolldicenode.cpp +++ b/node/rerolldicenode.cpp @@ -1,5 +1,6 @@ #include "rerolldicenode.h" #include "parsingtoolbox.h" +#include <utility> RerollDiceNode::RerollDiceNode(bool reroll, bool addingMode) : m_diceResult(new DiceResult()), m_validator(nullptr), m_reroll(reroll), m_adding(addingMode) @@ -26,7 +27,6 @@ void RerollDiceNode::run(ExecutionNode* previous) for(auto& die : previous_result->getResultList()) { Die* tmpdie= new Die(*die); - //*tmpdie= *die; m_diceResult->insertResult(tmpdie); die->displayed(); } @@ -35,10 +35,22 @@ void RerollDiceNode::run(ExecutionNode* previous) QList<Die*>& list= m_diceResult->getResultList(); QList<Die*> toRemove; - for(int i= 0; i < list.size(); ++i) + for(auto& die : list) { - auto die= list.at(i); bool finished= false; + auto state + = m_validator->isValidRangeSize(std::make_pair<qint64, qint64>(die->getBase(), die->getMaxValue())); + if((Dice::CONDITION_STATE::ALWAYSTRUE == state && m_adding) + || (!m_reroll && !m_adding && state == Dice::CONDITION_STATE::UNREACHABLE)) + { + m_errors.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR, + QObject::tr("Condition (%1) cause an endless loop with this dice: %2") + .arg(toString(true)) + .arg(QStringLiteral("d[%1,%2]") + .arg(static_cast<int>(die->getBase())) + .arg(static_cast<int>(die->getMaxValue())))); + continue; + } while(m_validator->hasValid(die, false) && !finished) { if(m_instruction != nullptr) @@ -52,8 +64,8 @@ void RerollDiceNode::run(ExecutionNode* previous) { toRemove.append(die); list.append(lastResult->getResultList()); + lastResult->clear(); } - lastResult->clear(); } } else @@ -79,7 +91,8 @@ void RerollDiceNode::run(ExecutionNode* previous) } else { - m_errors.insert(ExecutionNode::DIE_RESULT_EXPECTED, + m_errors.insert( + Dice::ERROR_CODE::DIE_RESULT_EXPECTED, QObject::tr( " The a operator expects dice result. Please check the documentation and fix your command.")); } diff --git a/node/scalaroperatornode.cpp b/node/scalaroperatornode.cpp index 3a26fc7..821150b 100644 --- a/node/scalaroperatornode.cpp +++ b/node/scalaroperatornode.cpp @@ -66,31 +66,39 @@ void ScalarOperatorNode::run(ExecutionNode* previous) m_internalNode->getResult()->setPrevious(previousResult); } + if(internalResult == nullptr) + { + m_errors.insert(Dice::ERROR_CODE::NO_VALID_RESULT, + QObject::tr("No Valid result in arithmetic operatoion: %1").arg(toString(true))); + return; + } + switch(m_arithmeticOperator) { case Die::PLUS: - m_scalarResult->setValue(add(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal())); + m_scalarResult->setValue(add(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())); break; case Die::MINUS: - m_scalarResult->setValue(substract(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal())); + m_scalarResult->setValue(substract(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())); break; case Die::MULTIPLICATION: - m_scalarResult->setValue(multiple(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal())); + m_scalarResult->setValue(multiple(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())); break; case Die::DIVIDE: - m_scalarResult->setValue(divide(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal())); + m_scalarResult->setValue(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())); break; case Die::INTEGER_DIVIDE: - m_scalarResult->setValue(static_cast<int>(divide(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal()))); + m_scalarResult->setValue( + static_cast<int>(divide(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal()))); break; case Die::POW: - m_scalarResult->setValue(pow(previousResult->getResult(Result::SCALAR).toReal(), - internalResult->getResult(Result::SCALAR).toReal())); + m_scalarResult->setValue(pow(previousResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal(), + internalResult->getResult(Dice::RESULT_TYPE::SCALAR).toReal())); break; } } @@ -128,7 +136,7 @@ qreal ScalarOperatorNode::divide(qreal a, qreal b) { if(qFuzzyCompare(b, 0)) { - m_errors.insert(DIVIDE_BY_ZERO, QObject::tr("Division by zero")); + m_errors.insert(Dice::ERROR_CODE::DIVIDE_BY_ZERO, QObject::tr("Division by zero")); return 0; } return static_cast<qreal>(a / b); @@ -240,12 +248,12 @@ void ScalarOperatorNode::generateDotTree(QString& s) } s.append(str); } -QMap<ExecutionNode::DICE_ERROR_CODE, QString> ScalarOperatorNode::getExecutionErrorMap() +QMap<Dice::ERROR_CODE, QString> ScalarOperatorNode::getExecutionErrorMap() { if(nullptr != m_internalNode) { auto keys= m_internalNode->getExecutionErrorMap().keys(); - for(ExecutionNode::DICE_ERROR_CODE& key : keys) + for(const auto& key : keys) { m_errors.insert(key, m_internalNode->getExecutionErrorMap().value(key)); } @@ -253,7 +261,7 @@ QMap<ExecutionNode::DICE_ERROR_CODE, QString> ScalarOperatorNode::getExecutionEr if(nullptr != m_nextNode) { auto keys= m_nextNode->getExecutionErrorMap().keys(); - for(ExecutionNode::DICE_ERROR_CODE& key : keys) + for(auto const& key : keys) { m_errors.insert(key, m_nextNode->getExecutionErrorMap().value(key)); } diff --git a/node/scalaroperatornode.h b/node/scalaroperatornode.h index 2ac89b0..a58a8d3 100644 --- a/node/scalaroperatornode.h +++ b/node/scalaroperatornode.h @@ -76,7 +76,7 @@ public: * @brief getErrorList * @return */ - virtual QMap<ExecutionNode::DICE_ERROR_CODE, QString> getExecutionErrorMap(); + virtual QMap<Dice::ERROR_CODE, QString> getExecutionErrorMap(); /** * @brief getArithmeticOperator * @return diff --git a/node/valueslistnode.cpp b/node/valueslistnode.cpp index b31ee84..d378350 100644 --- a/node/valueslistnode.cpp +++ b/node/valueslistnode.cpp @@ -16,7 +16,7 @@ void ValuesListNode::run(ExecutionNode* previous) auto result= node->getResult(); if(!result) continue; - auto val= result->getResult(Result::SCALAR).toInt(); + auto val= result->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); Die* die= new Die(); auto dyna= dynamic_cast<VariableNode*>(node); if(nullptr != dyna) diff --git a/node/variablenode.cpp b/node/variablenode.cpp index 1d13a2c..e45214d 100644 --- a/node/variablenode.cpp +++ b/node/variablenode.cpp @@ -24,7 +24,7 @@ void VariableNode::run(ExecutionNode* previous) } else { - m_errors.insert(NO_VARIBALE, QObject::tr("No variable at index:%1").arg(m_index + 1)); + m_errors.insert(Dice::ERROR_CODE::NO_VARIBALE, QObject::tr("No variable at index:%1").arg(m_index + 1)); } } diff --git a/operationcondition.cpp b/operationcondition.cpp index 53a994d..9ef8e1e 100644 --- a/operationcondition.cpp +++ b/operationcondition.cpp @@ -41,6 +41,10 @@ void OperationCondition::setBoolean(BooleanCondition* boolean) qint64 OperationCondition::hasValid(Die* b, bool recursive, bool unhighlight) const { + if(nullptr == m_boolean) + { + return 0; + } QList<qint64> listValues; if(recursive) { @@ -64,7 +68,7 @@ qint64 OperationCondition::hasValid(Die* b, bool recursive, bool unhighlight) co if(valueScalar == 0) valueScalar= 1; die.insertRollValue(value % valueScalar); - sum+= m_boolean->hasValid(&die, recursive, false); + sum+= m_boolean->hasValid(&die, recursive, false) ? 1 : 0; } break; } @@ -102,18 +106,26 @@ QString OperationCondition::toString() } return QStringLiteral("[%1%2%3]").arg(str).arg(valueToScalar()).arg(m_boolean->toString()); } -bool OperationCondition::isValidRangeSize(std::pair<qint64, qint64>) const +Dice::CONDITION_STATE OperationCondition::isValidRangeSize(const std::pair<qint64, qint64>& range) const { - auto value= valueToScalar(); - bool valid= true; + Dice::CONDITION_STATE valid= Dice::CONDITION_STATE::REACHABLE; + + auto rangeIsClose= (range.first == range.second); - if(value == 0) - valid= false; - /* else if(nullptr != m_boolean) - valid = m_boolean->isValidRangeSize(range);*/ + Die die; + die.insertRollValue(range.first); + + if(nullptr == m_boolean) + return Dice::CONDITION_STATE::ERROR; + + if(rangeIsClose && m_boolean->hasValid(&die, false, false)) + valid= Dice::CONDITION_STATE::ALWAYSTRUE; + else if(rangeIsClose && !m_boolean->hasValid(&die, false, false)) + valid= Dice::CONDITION_STATE::UNREACHABLE; return valid; } + Validator* OperationCondition::getCopy() const { OperationCondition* val= new OperationCondition(); @@ -131,5 +143,22 @@ qint64 OperationCondition::valueToScalar() const m_value->run(nullptr); auto result= m_value->getResult(); - return result->getResult(Result::SCALAR).toInt(); + return result->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); +} + +const std::set<qint64>& OperationCondition::getPossibleValues(const std::pair<qint64, qint64>& range) +{ + if(nullptr == m_boolean) + return m_values; + + for(qint64 i= std::min(range.first, range.second); i <= std::max(range.first, range.second); ++i) + { + auto valueScalar= valueToScalar(); + auto val= i % valueScalar; + Die die; + die.insertRollValue(val); + if(m_boolean->hasValid(&die, false, false)) + m_values.insert(i); + } + return m_values; } diff --git a/operationcondition.h b/operationcondition.h index 86562e6..002a669 100644 --- a/operationcondition.h +++ b/operationcondition.h @@ -34,27 +34,29 @@ public: Modulo }; OperationCondition(); - virtual ~OperationCondition(); + virtual ~OperationCondition() override; - virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const; + virtual qint64 hasValid(Die* b, bool recursive, bool unhighlight= false) const override; void setOperator(ConditionOperator m); // void setValue(qint64); void setValueNode(ExecutionNode* node); - QString toString(); + QString toString() override; - virtual bool isValidRangeSize(std::pair<qint64, qint64> range) const; + virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override; BooleanCondition* getBoolean() const; void setBoolean(BooleanCondition* boolean); - virtual Validator* getCopy() const; + virtual Validator* getCopy() const override; + + const std::set<qint64>& getPossibleValues(const std::pair<qint64, qint64>& range) override; private: qint64 valueToScalar() const; private: - ConditionOperator m_operator; + ConditionOperator m_operator= Modulo; BooleanCondition* m_boolean= nullptr; // qint64 m_value; ExecutionNode* m_value= nullptr; diff --git a/parsingtoolbox.cpp b/parsingtoolbox.cpp index 702019d..4372b41 100644 --- a/parsingtoolbox.cpp +++ b/parsingtoolbox.cpp @@ -204,13 +204,17 @@ Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare) { OperationCondition* condition= new OperationCondition(); condition->setValueNode(operandNode); - Validator* valid= readValidator(str,hasSquare); + Validator* valid= readValidator(str, hasSquare); BooleanCondition* boolC= dynamic_cast<BooleanCondition*>(valid); if(nullptr != boolC) { condition->setBoolean(boolC); + returnVal= condition; + } + else + { + delete condition; } - returnVal= condition; } } else if(readOperand(str, operandNode)) @@ -277,16 +281,16 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) Validator* tmp= readValidator(str, expectSquareBrasket); CompositeValidator::LogicOperation opLogic; - QVector<CompositeValidator::LogicOperation>* operators= new QVector<CompositeValidator::LogicOperation>(); - QList<Validator*>* validatorList= new QList<Validator*>(); + QVector<CompositeValidator::LogicOperation> operators; + QList<Validator*> validatorList; while(nullptr != tmp) { bool hasOperator= readLogicOperation(str, opLogic); if(hasOperator) { - operators->append(opLogic); - validatorList->append(tmp); + operators.append(opLogic); + validatorList.append(tmp); tmp= readValidator(str, expectSquareBrasket); } else @@ -297,19 +301,19 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) // isOk=true; } - if(!validatorList->isEmpty()) + if(!validatorList.isEmpty()) { - validatorList->append(tmp); + validatorList.append(tmp); } else { - delete operators; + operators.clear(); return tmp; } tmp= nullptr; } } - if(!validatorList->isEmpty()) + if(!validatorList.isEmpty()) { CompositeValidator* validator= new CompositeValidator(); validator->setOperationList(operators); @@ -318,7 +322,6 @@ Validator* ParsingToolBox::readCompositeValidator(QString& str) } else { - delete operators; return nullptr; } } @@ -597,19 +600,13 @@ bool ParsingToolBox::readAscending(QString& str) } return false; } -bool ParsingToolBox::isValidValidator(ExecutionNode* previous, Validator* val) +Dice::CONDITION_STATE ParsingToolBox::isValidValidator(ExecutionNode* previous, Validator* val) { DiceRollerNode* node= getDiceRollerNode(previous); - bool valid= false; - if(nullptr != node) - { - valid= val->isValidRangeSize(node->getRange()); - } - else - { - valid= true; - } - return valid; + if(nullptr == node) + return Dice::CONDITION_STATE::ERROR; + + return val->isValidRangeSize(node->getRange()); } DiceRollerNode* ParsingToolBox::getDiceRollerNode(ExecutionNode* previous) { @@ -663,28 +660,32 @@ ParsingToolBox::LIST_OPERATOR ParsingToolBox::readListOperator(QString& str) return NONE; } -void ParsingToolBox::readPainterParameter(PainterNode* painter, QString& str) +bool ParsingToolBox::readPainterParameter(PainterNode* painter, QString& str) { - if(str.startsWith('[')) - { - str= str.remove(0, 1); - int pos= str.indexOf(']'); + if(!str.startsWith('[')) + return false; + + str= str.remove(0, 1); + int pos= str.indexOf(']'); + + if(pos == -1) + return false; - if(pos > -1) + QString data= str.left(pos); + str= str.remove(0, pos + 1); + QStringList duos= data.split(','); + bool result= false; + for(QString& duoStr : duos) + { + QStringList keyValu= duoStr.split(':'); + if(keyValu.size() == 2) { - QString data= str.left(pos); - str= str.remove(0, pos + 1); - QStringList duos= data.split(','); - for(QString& duoStr : duos) - { - QStringList keyValu= duoStr.split(':'); - if(keyValu.size() == 2) - { - painter->insertColorItem(keyValu[1], keyValu[0].toInt()); - } - } + painter->insertColorItem(keyValu[1], keyValu[0].toInt()); + result= true; } } + + return result; } QHash<QString, QString> ParsingToolBox::getVariableHash() @@ -58,12 +58,20 @@ QString Range::toString() { return QStringLiteral("[%1-%2]").arg(m_start).arg(m_end); } -bool Range::isValidRangeSize(std::pair<qint64, qint64> range) const +Dice::CONDITION_STATE Range::isValidRangeSize(const std::pair<qint64, qint64>& range) const { - auto newStart= qBound(range.first, m_start, range.second); - auto newEnd= qBound(range.first, m_end, range.second); + auto minRange= std::min(m_start, m_end); + auto minPossibleValue= std::min(range.first, range.second); - return (newStart == m_start && newEnd == m_end && m_end >= m_start); + auto maxRange= std::max(m_start, m_end); + auto maxPossibleValue= std::max(range.first, range.second); + + if(minRange == minPossibleValue && maxRange == maxPossibleValue) + return Dice::CONDITION_STATE::ALWAYSTRUE; + else if(maxRange < minPossibleValue || minRange > maxPossibleValue) + return Dice::CONDITION_STATE::UNREACHABLE; + else + return Dice::CONDITION_STATE::UNREACHABLE; } void Range::setStart(qint64 start) { @@ -35,10 +35,10 @@ public: void setValue(qint64, qint64); void setStart(qint64); void setEnd(qint64); - virtual qint64 hasValid(Die* b, bool recursive, bool unlight= false) const; + virtual qint64 hasValid(Die* b, bool recursive, bool unlight= false) const override; - virtual QString toString(); - virtual bool isValidRangeSize(std::pair<qint64, qint64> range) const; + virtual QString toString() override; + virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const override; bool isFullyDefined() const; qint64 getStart() const; @@ -47,7 +47,7 @@ public: void setEmptyRange(bool); bool isEmptyRange(); - virtual Validator* getCopy() const; + virtual Validator* getCopy() const override; private: qint64 m_start= 0; diff --git a/result/diceresult.cpp b/result/diceresult.cpp index e66fc4f..23b925e 100644 --- a/result/diceresult.cpp +++ b/result/diceresult.cpp @@ -25,7 +25,7 @@ DiceResult::DiceResult() : m_operator(Die::PLUS) { - m_resultTypes= (DICE_LIST | SCALAR); + m_resultTypes= (static_cast<int>(Dice::RESULT_TYPE::DICE_LIST) | static_cast<int>(Dice::RESULT_TYPE::SCALAR)); m_homogeneous= true; } void DiceResult::insertResult(Die* die) @@ -63,15 +63,15 @@ DiceResult::~DiceResult() m_diceValues.clear(); } } -QVariant DiceResult::getResult(RESULT_TYPE type) +QVariant DiceResult::getResult(Dice::RESULT_TYPE type) { switch(type) { - case SCALAR: + case Dice::RESULT_TYPE::SCALAR: { return getScalarResult(); } - case DICE_LIST: + case Dice::RESULT_TYPE::DICE_LIST: { return QVariant(); } diff --git a/result/diceresult.h b/result/diceresult.h index 54e0b57..ce8ffb7 100644 --- a/result/diceresult.h +++ b/result/diceresult.h @@ -61,7 +61,7 @@ public: * @brief getScalar * @return */ - virtual QVariant getResult(RESULT_TYPE); + virtual QVariant getResult(Dice::RESULT_TYPE); /** * @brief toString * @return diff --git a/result/result.cpp b/result/result.cpp index edd00e4..983f1f4 100644 --- a/result/result.cpp +++ b/result/result.cpp @@ -22,7 +22,10 @@ #include "result.h" #include <QUuid> -Result::Result() : m_resultTypes(NONE), m_id(QString("\"%1\"").arg(QUuid::createUuid().toString())), m_previous(nullptr) +Result::Result() + : m_resultTypes(static_cast<int>(Dice::RESULT_TYPE::NONE)) + , m_id(QString("\"%1\"").arg(QUuid::createUuid().toString())) + , m_previous(nullptr) { } Result::~Result() {} @@ -43,9 +46,9 @@ bool Result::isStringResult() const return false; } void Result::clear() {} -bool Result::hasResultOfType(RESULT_TYPE type) const +bool Result::hasResultOfType(Dice::RESULT_TYPE type) const { - return (m_resultTypes & type); + return (m_resultTypes & static_cast<int>(type)); } void Result::generateDotTree(QString& s) { diff --git a/result/result.h b/result/result.h index 8f31c05..76f3a8c 100644 --- a/result/result.h +++ b/result/result.h @@ -22,7 +22,7 @@ #ifndef RESULT_H #define RESULT_H -//#include <Qt> +#include "diceparserhelper.h" #include <QString> #include <QVariant> /** @@ -32,16 +32,6 @@ class Result { public: /** - * @brief The RESULT_TYPE enum or combinaison - */ - enum RESULT_TYPE - { - NONE= 0, - SCALAR= 1, - STRING= 2, - DICE_LIST= 4 - }; - /** * @brief Result */ Result(); @@ -54,12 +44,12 @@ public: * @brief isScalar * @return */ - virtual bool hasResultOfType(RESULT_TYPE) const; + virtual bool hasResultOfType(Dice::RESULT_TYPE) const; /** * @brief getScalar * @return */ - virtual QVariant getResult(RESULT_TYPE)= 0; + virtual QVariant getResult(Dice::RESULT_TYPE)= 0; /** * @brief getPrevious * @return @@ -100,7 +90,7 @@ protected: QString m_id; private: - Result* m_previous; /// @brief + Result* m_previous= nullptr; /// @brief }; #endif // RESULT_H diff --git a/result/scalarresult.cpp b/result/scalarresult.cpp index 089c4b8..d901c08 100644 --- a/result/scalarresult.cpp +++ b/result/scalarresult.cpp @@ -23,16 +23,16 @@ ScalarResult::ScalarResult() { - m_resultTypes= Result::SCALAR; + m_resultTypes= static_cast<int>(Dice::RESULT_TYPE::SCALAR); } void ScalarResult::setValue(qreal i) { m_value= i; } -QVariant ScalarResult::getResult(Result::RESULT_TYPE type) +QVariant ScalarResult::getResult(Dice::RESULT_TYPE type) { - if(SCALAR == type) + if(Dice::RESULT_TYPE::SCALAR == type) { return m_value; } diff --git a/result/scalarresult.h b/result/scalarresult.h index c20de0f..1eac73c 100644 --- a/result/scalarresult.h +++ b/result/scalarresult.h @@ -39,7 +39,7 @@ public: * @brief getResult * @return */ - virtual QVariant getResult(Result::RESULT_TYPE); + virtual QVariant getResult(Dice::RESULT_TYPE); /** * @brief setValue * @param i diff --git a/result/stringresult.cpp b/result/stringresult.cpp index a44e24e..d5a7880 100644 --- a/result/stringresult.cpp +++ b/result/stringresult.cpp @@ -3,20 +3,21 @@ StringResult::StringResult() { m_highlight= true; - m_resultTypes= Result::STRING; + m_resultTypes= static_cast<int>(Dice::RESULT_TYPE::STRING); } void StringResult::setText(QString text) { m_value= text; } StringResult::~StringResult() {} -bool StringResult::hasResultOfType(RESULT_TYPE resultType) const +bool StringResult::hasResultOfType(Dice::RESULT_TYPE resultType) const { - if(resultType & Result::STRING) + + if(resultType == Dice::RESULT_TYPE::STRING) { return true; } - else if(resultType & Result::SCALAR) + else if(resultType == Dice::RESULT_TYPE::SCALAR) { bool ok= false; getText().toInt(&ok); @@ -28,13 +29,13 @@ QString StringResult::getText() const { return m_value; } -QVariant StringResult::getResult(RESULT_TYPE type) +QVariant StringResult::getResult(Dice::RESULT_TYPE type) { switch(type) { - case STRING: + case Dice::RESULT_TYPE::STRING: return getText(); - case SCALAR: + case Dice::RESULT_TYPE::SCALAR: return getText().toInt(); default: return QVariant(); diff --git a/result/stringresult.h b/result/stringresult.h index ec6c3ce..0e469fe 100644 --- a/result/stringresult.h +++ b/result/stringresult.h @@ -31,7 +31,7 @@ public: * @brief getScalar * @return */ - virtual QVariant getResult(RESULT_TYPE); + virtual QVariant getResult(Dice::RESULT_TYPE); /** * @brief toString * @return @@ -40,7 +40,7 @@ public: virtual void setHighLight(bool); virtual bool hasHighLight() const; - virtual bool hasResultOfType(RESULT_TYPE resultType) const; + virtual bool hasResultOfType(Dice::RESULT_TYPE resultType) const; virtual Result* getCopy() const; private: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4065cc5..6fb276b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,2 @@ -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra") -set(CMAKE_AUTOMOC ON) -find_package(Qt5Test REQUIRED) - -set(test_source testnode.cpp tst_dice.cpp) - -add_executable(test_dice ${test_source} ) -target_link_libraries(test_dice diceparser Qt5::Test) -add_test(tst_diceparser test_dice) +#add_subdirectory(fuzzer) +add_subdirectory(dice) diff --git a/tests/dice/CMakeLists.txt b/tests/dice/CMakeLists.txt index a0f27fd..d254624 100644 --- a/tests/dice/CMakeLists.txt +++ b/tests/dice/CMakeLists.txt @@ -1,17 +1,12 @@ -cmake_minimum_required(VERSION 3.5) -project(tst_diceParser) - -enable_testing(true) - -# Tell CMake to run moc when necessary: +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra") set(CMAKE_AUTOMOC ON) +find_package(Qt5Test REQUIRED) -# As moc files are generated in the binary dir, tell CMake -# to always look for includes there: -set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(test_source testnode.cpp tst_dice.cpp) -find_package(Qt5Test REQUIRED) +add_executable(test_dice ${test_source} ${dice_sources}) -add_test(tst_diceParser tst_dice.cpp) +target_include_directories(test_dice PRIVATE ../../include) -target_link_libraries(foo Qt5::Test) +target_link_libraries(test_dice Qt5::Test) +add_test(tst_diceparser test_dice) diff --git a/tests/dice/Dice.pro b/tests/dice/Dice.pro deleted file mode 100644 index 9d24f91..0000000 --- a/tests/dice/Dice.pro +++ /dev/null @@ -1,25 +0,0 @@ -include(../tests.pri) - -SOURCES += \ - tst_dice.cpp - -TEMPLATE = app -TARGET= tst_diceParser -MOC_DIR=trash -OBJECTS_DIR=trash - -CONFIG+=testcase - -QT += testlib quick qml widgets - -INCLUDEPATH += $$ROLISTEAMSRC/diceparser/ -INCLUDEPATH += $$ROLISTEAMSRC/diceparser/node -INCLUDEPATH += $$ROLISTEAMSRC/diceparser/result - - -include($$ROLISTEAMSRC/diceparser/diceparser.pri) - -HEADERS -= ../../../rolisteam/client/diceparser/qmltypesregister.h -SOURCES -= ../../../rolisteam/client/diceparser/qmltypesregister.cpp - - diff --git a/tests/testnode.cpp b/tests/dice/testnode.cpp index de9fc05..de9fc05 100644 --- a/tests/testnode.cpp +++ b/tests/dice/testnode.cpp diff --git a/tests/testnode.h b/tests/dice/testnode.h index 5c918ee..5c918ee 100644 --- a/tests/testnode.h +++ b/tests/dice/testnode.h diff --git a/tests/tst_dice.cpp b/tests/dice/tst_dice.cpp index 1fe2641..a35f918 100644 --- a/tests/tst_dice.cpp +++ b/tests/dice/tst_dice.cpp @@ -43,6 +43,7 @@ #include "node/splitnode.h" #include "node/stringnode.h" #include "node/uniquenode.h" +#include "operationcondition.h" #include "result/stringresult.h" #include "testnode.h" @@ -131,6 +132,8 @@ private slots: void occurenceTest(); void occurenceTest_data(); + void operatoionConditionValidatorTest(); + private: std::unique_ptr<Die> m_die; std::unique_ptr<DiceParser> m_diceParser; @@ -463,13 +466,13 @@ void TestDice::dangerousCommandsTest_data() // QTest::addRow("cmd5") << "10d10g10"; } -void makeResult(DiceResult& result, const QVector<int>& values) +void makeResult(DiceResult& result, const QVector<int>& values, int base= 1, int max= 10) { for(int val : values) { auto die= new Die(); - die->setBase(1); - die->setMaxValue(10); + die->setBase(base); + die->setMaxValue(max); die->insertRollValue(val); result.insertResult(die); } @@ -524,7 +527,7 @@ void TestDice::keepTest() if(error) return; - auto resultScore= keepN.getResult()->getResult(Result::SCALAR).toInt(); + auto resultScore= keepN.getResult()->getResult(Dice::RESULT_TYPE::SCALAR).toInt(); QCOMPARE(score, resultScore); } @@ -609,7 +612,7 @@ void TestDice::countTest() node.run(nullptr); - QCOMPARE(score, countN.getResult()->getResult(Result::SCALAR).toInt()); + QCOMPARE(score, countN.getResult()->getResult(Dice::RESULT_TYPE::SCALAR).toInt()); countN.setValidator(nullptr); } @@ -722,7 +725,7 @@ void TestDice::rerollUntilTest() RerollDiceNode reroll(false, false); DiceResult result; - makeResult(result, values); + makeResult(result, values, 0); node.setResult(&result); auto validator= makeValidator(condition, BooleanCondition::Equal); @@ -742,7 +745,6 @@ void TestDice::rerollUntilTest() resultDiff= true; ++i; } - QCOMPARE(different, resultDiff); } void TestDice::rerollUntilTest_data() @@ -1062,6 +1064,31 @@ void TestDice::ifCommandTest_data() << QStringList({"Complete Success:", "Success with Complications:", "Failure:"}); } +void TestDice::operatoionConditionValidatorTest() +{ + OperationCondition validator; + NumberNode number; + number.setNumber(2); + validator.setValueNode(&number); + + BooleanCondition subValidator; + subValidator.setOperator(BooleanCondition::Equal); + NumberNode subnumber; + subnumber.setNumber(0); + subValidator.setValueNode(&subnumber); + + validator.setBoolean(&subValidator); + + std::set<qint64> data= {2, 4, 6, 8, 10}; + auto value= validator.getPossibleValues(std::make_pair<qint64, qint64>(1, 10)); + + subValidator.setValueNode(nullptr); + validator.setValueNode(nullptr); + validator.setBoolean(nullptr); + + QCOMPARE(value, data); +} + void TestDice::cleanupTestCase() {} QTEST_MAIN(TestDice) diff --git a/tests/fuzzer/CMakeLists.txt b/tests/fuzzer/CMakeLists.txt new file mode 100644 index 0000000..c6d94ca --- /dev/null +++ b/tests/fuzzer/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-permissive -pedantic -Wall -Wextra") +set(CMAKE_AUTOMOC ON) + +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) +find_package(Qt5Svg REQUIRED) +find_package(Qt5Concurrent REQUIRED) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +#SET (CMAKE_EXE_LINKER_FLAGS "-static") + +add_definitions(-DPAINTER_OP) +set(MODE "cli") + + + +set(fdsource testcase.cpp) + +add_executable(fuzzTestCase ${fdsource} ) + + +target_link_libraries(fuzzTestCase libdiceparser.a Qt5::Core Qt5::Gui Qt5::Svg Qt5::Concurrent) +#target_link_libraries(fuzzTestCase ) diff --git a/tests/fuzzer/run_test.sh b/tests/fuzzer/run_test.sh new file mode 100755 index 0000000..9ecdeef --- /dev/null +++ b/tests/fuzzer/run_test.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +rm -rf build +mkdir build +cd build +CC=afl-gcc CXX=afl-g++ cmake ../ -DSTATIC_BUILD=ON && make +#export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" + + +#./fuzzTestCase ../testcase_dir/gooddata.txt +# afl-fuzz -m 2G -i ../testcase_dir -o ../findings_dir ./fuzzTestCase @@ +afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -M fuzzer01 ./fuzzTestCase @@ & +screen -S fuzz1 -d -m touch afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -S fuzzer02 ./fuzzTestCase @@ & +screen -S fuzz2 -d -m touch afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -S fuzzer03 ./fuzzTestCase @@ & +screen -S fuzz3 -d -m touch afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -S fuzzer04 ./fuzzTestCase @@ & +screen -S fuzz4 -d -m touch afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -S fuzzer05 ./fuzzTestCase @@ & +screen -S fuzz5 -d -m touch afl-fuzz -m 2G -i ../testcase_dir -o ../sync_dir -S fuzzer06 ./fuzzTestCase @@ + + + +# as root + +# echo core >/proc/sys/kernel/core_pattern + +# echo performance | tee cpu*/cpufreq/scaling_governor + +# echo ondemand | tee cpu*/cpufreq/scaling_governor diff --git a/tests/fuzzer/testcase.cpp b/tests/fuzzer/testcase.cpp new file mode 100644 index 0000000..87d1867 --- /dev/null +++ b/tests/fuzzer/testcase.cpp @@ -0,0 +1,37 @@ +#include <QCoreApplication> +#include <QDebug> +#include <QFile> +#include <diceparser.h> + +static DiceParser* parser= new DiceParser(); + +void runCommand(const QString& cmd) +{ + qDebug() << "cmd" << cmd; + if(parser->parseLine(cmd)) + { + parser->start(); + } +} + +int main(int argc, char** argv) +{ + // qDebug() << "first"; + QCoreApplication app(argc, argv); + + // qDebug() << "start"; + QFile file(app.arguments().at(1)); + // qDebug() << "file" << app.arguments().at(1); + if(!file.open(QIODevice::ReadOnly)) + return 1; + + auto line= file.readLine(); + while(!line.isEmpty()) + { + // qDebug() << line; + runCommand(QString::fromUtf8(line)); + line= file.readLine(); + } + + return 0; +} diff --git a/tests/fuzzer/testcase_dir/gooddata.txt b/tests/fuzzer/testcase_dir/gooddata.txt new file mode 100644 index 0000000..d62c87e --- /dev/null +++ b/tests/fuzzer/testcase_dir/gooddata.txt @@ -0,0 +1,45 @@ +1L[cheminée,chocolat,épée,arc,chute de pierre[40]] +10d10c[>=6]-@c[=1] +1+1D10 +1+(4*3)D10s +2+4/4 +2D10*2D20*8 +1D100a[>=95]a[>=96]a[>=97]a[>=98]a[>=99]e[>=100] +15D10e10c[8-10] +(4+4)^4 +(1d20+20)*7/10 +20*7/10 +2d6c[%2=0] +D25;D10 +8+8+8 +1D20-88 +100*1D20*2D6 +2D6 # comment +100/28*3 +help +la +10D10c[<2|>7] +10D6c[=2|=4|=6] +10D10e[=1|=10]k4 +1L[t,b,s,r,j,v,i,p[8-10]] +1d6e6;1d4e4mk1 +400D20/400000 +1d100e[>=95]i[<5]{-1d100e95} +1d100i[<70]{1d10i[=10]{1d100i[<70]{1d10e10}}} +5-5*5+5 +((3+4)*2)d6 +4d6i[=6]{+1d6} +10d[-8--1] +4d6e6i[=4]{-4} +4d6e6f[!=4] +5d10g10 +4d6p[4:blue] +10d[0-9] +1d8e8;1d6e6mk1+2 +3d100g5 +2d10k1+2d10k1+2d10k1 +(1)-1d6e6 +8d10o +[100,200,300]k2 +100;200;300;[$1,$2,$3]k2 +0-2;$1+$1;$2i:[<1]{1}{0} diff --git a/validator.cpp b/validator.cpp index aba97c6..9f717f8 100644 --- a/validator.cpp +++ b/validator.cpp @@ -23,3 +23,8 @@ Validator::Validator() {} Validator::~Validator() {} + +const std::set<qint64>& Validator::getPossibleValues(const std::pair<qint64, qint64>&) +{ + return m_values; +} diff --git a/validator.h b/validator.h index 469a6fe..a1e7d65 100644 --- a/validator.h +++ b/validator.h @@ -22,9 +22,11 @@ #ifndef VALIDATOR_H #define VALIDATOR_H +#include "diceparserhelper.h" #include "die.h" #include <QString> #include <Qt> +#include <set> /** * @brief The Validator class is an abstract class for checking the validity of dice for some * operator. @@ -58,12 +60,17 @@ public: * @param faces * @return */ - virtual bool isValidRangeSize(std::pair<qint64, qint64> range) const= 0; + virtual Dice::CONDITION_STATE isValidRangeSize(const std::pair<qint64, qint64>& range) const= 0; /** * @brief getCopy * @return return a copy of this validator */ virtual Validator* getCopy() const= 0; + + virtual const std::set<qint64>& getPossibleValues(const std::pair<qint64, qint64>& range); + +protected: + std::set<qint64> m_values; }; #endif // VALIDATOR_H |