aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/libparser/parsingtoolbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libparser/parsingtoolbox.cpp')
-rw-r--r--src/libparser/parsingtoolbox.cpp2641
1 files changed, 2641 insertions, 0 deletions
diff --git a/src/libparser/parsingtoolbox.cpp b/src/libparser/parsingtoolbox.cpp
new file mode 100644
index 0000000..dfde37f
--- /dev/null
+++ b/src/libparser/parsingtoolbox.cpp
@@ -0,0 +1,2641 @@
+/***************************************************************************
+ * Copyright (C) 2014 by Renaud Guezennec *
+ * https://rolisteam.org/contact *
+ * *
+ * This file is part of DiceParser *
+ * *
+ * DiceParser is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "diceparser/parsingtoolbox.h"
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QRegularExpression>
+#include <QString>
+#include <set>
+
+#include "node/allsamenode.h"
+#include "node/bind.h"
+#include "node/countexecutenode.h"
+#include "node/dicerollernode.h"
+#include "node/executionnode.h"
+#include "node/explodedicenode.h"
+#include "node/filternode.h"
+#include "node/groupnode.h"
+#include "node/helpnode.h"
+#include "node/ifnode.h"
+#include "node/jumpbackwardnode.h"
+#include "node/keepdiceexecnode.h"
+#include "node/listaliasnode.h"
+#include "node/listsetrollnode.h"
+#include "node/mergenode.h"
+#include "node/numbernode.h"
+#include "node/occurencecountnode.h"
+#include "node/paintnode.h"
+#include "node/parenthesesnode.h"
+#include "node/repeaternode.h"
+#include "node/replacevaluenode.h"
+#include "node/rerolldicenode.h"
+#include "node/scalaroperatornode.h"
+#include "node/sortresult.h"
+#include "node/splitnode.h"
+#include "node/startingnode.h"
+#include "node/stringnode.h"
+#include "node/switchcasenode.h"
+#include "node/uniquenode.h"
+#include "node/valueslistnode.h"
+#include "node/variablenode.h"
+#include "operationcondition.h"
+#include "range.h"
+#include "validatorlist.h"
+
+QHash<QString, QString> ParsingToolBox::m_variableHash;
+
+ParsingToolBox::ParsingToolBox()
+{
+ // m_logicOp = ;
+ m_logicOp.insert(">=", Dice::CompareOperator::GreaterOrEqual);
+ m_logicOp.insert("<=", Dice::CompareOperator::LesserOrEqual);
+ m_logicOp.insert("<", Dice::CompareOperator::LesserThan);
+ m_logicOp.insert("=", Dice::CompareOperator::Equal);
+ m_logicOp.insert(">", Dice::CompareOperator::GreaterThan);
+ m_logicOp.insert("!=", Dice::CompareOperator::Different);
+
+ // m_logicOperation = ;
+ m_logicOperation.insert("|", Dice::LogicOperation::OR);
+ m_logicOperation.insert("^", Dice::LogicOperation::EXCLUSIVE_OR);
+ m_logicOperation.insert("&", Dice::LogicOperation::AND);
+
+ // m_conditionOperation = ;
+ m_conditionOperation.insert("%", Dice::ConditionOperator::Modulo);
+
+ // m_arithmeticOperation = new QHash<QString,ScalarOperatorNode::ArithmeticOperator>();
+ m_arithmeticOperation.push_back({QStringLiteral("**"), Dice::ArithmeticOperator::POW});
+ m_arithmeticOperation.push_back({QStringLiteral("+"), Dice::ArithmeticOperator::PLUS});
+ m_arithmeticOperation.push_back({QStringLiteral("-"), Dice::ArithmeticOperator::MINUS});
+ m_arithmeticOperation.push_back({QStringLiteral("*"), Dice::ArithmeticOperator::MULTIPLICATION});
+ m_arithmeticOperation.push_back({QStringLiteral("x"), Dice::ArithmeticOperator::MULTIPLICATION});
+ m_arithmeticOperation.push_back({QStringLiteral("|"), Dice::ArithmeticOperator::INTEGER_DIVIDE});
+ m_arithmeticOperation.push_back({QStringLiteral("/"), Dice::ArithmeticOperator::DIVIDE});
+ m_arithmeticOperation.push_back({QStringLiteral("÷"), Dice::ArithmeticOperator::DIVIDE});
+
+ m_mapDiceOp.insert(QStringLiteral("D"), D);
+ m_mapDiceOp.insert(QStringLiteral("L"), L);
+
+ m_OptionOp.insert(QStringLiteral("k"), Keep);
+ m_OptionOp.insert(QStringLiteral("K"), KeepAndExplode);
+ m_OptionOp.insert(QStringLiteral("s"), Sort);
+ m_OptionOp.insert(QStringLiteral("c"), Count);
+ m_OptionOp.insert(QStringLiteral("r"), Reroll);
+ m_OptionOp.insert(QStringLiteral("e"), Explode);
+ m_OptionOp.insert(QStringLiteral("R"), RerollUntil);
+ m_OptionOp.insert(QStringLiteral("a"), RerollAndAdd);
+ m_OptionOp.insert(QStringLiteral("m"), Merge);
+ m_OptionOp.insert(QStringLiteral("i"), ifOperator);
+ m_OptionOp.insert(QStringLiteral("p"), Painter);
+ m_OptionOp.insert(QStringLiteral("f"), Filter);
+ m_OptionOp.insert(QStringLiteral("y"), Split);
+ m_OptionOp.insert(QStringLiteral("u"), Unique);
+ m_OptionOp.insert(QStringLiteral("t"), AllSameExplode);
+ m_OptionOp.insert(QStringLiteral("g"), Group);
+ m_OptionOp.insert(QStringLiteral("b"), Bind);
+ m_OptionOp.insert(QStringLiteral("o"), Occurences);
+ m_OptionOp.insert(QStringLiteral("S"), SwitchCaseOption);
+ m_OptionOp.insert(QStringLiteral("T"), TransformOption);
+
+ m_functionMap.insert({QStringLiteral("repeat"), REPEAT});
+
+ m_nodeActionMap.insert(QStringLiteral("@"), JumpBackward);
+
+ m_commandList.append(QStringLiteral("help"));
+ m_commandList.append(QStringLiteral("la"));
+}
+
+ParsingToolBox::ParsingToolBox(const ParsingToolBox&) {}
+ParsingToolBox::~ParsingToolBox() {}
+
+void ParsingToolBox::clearUp()
+{
+ m_errorMap.clear();
+ m_comment= QString("");
+}
+
+void ParsingToolBox::cleanUpAliases()
+{
+ m_aliasList.clear();
+}
+
+ExecutionNode* ParsingToolBox::addSort(ExecutionNode* e, bool b)
+{
+ SortResultNode* nodeSort= new SortResultNode();
+ nodeSort->setSortAscending(b);
+ if(nullptr != e)
+ e->setNextNode(nodeSort);
+ return nodeSort;
+}
+
+void ParsingToolBox::addError(Dice::ERROR_CODE code, const QString& msg)
+{
+ m_errorMap.insert(code, msg);
+}
+void ParsingToolBox::addWarning(Dice::ERROR_CODE code, const QString& msg)
+{
+ m_warningMap.insert(code, msg);
+}
+bool ParsingToolBox::readDiceLogicOperator(QString& str, Dice::ConditionOperator& op)
+{
+ QString longKey;
+ auto const& keys= m_conditionOperation.keys();
+ for(const QString& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_conditionOperation.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readArithmeticOperator(QString& str, Dice::ArithmeticOperator& op)
+{
+
+ auto it= std::find_if(m_arithmeticOperation.begin(), m_arithmeticOperation.end(),
+ [str](const std::pair<QString, Dice::ArithmeticOperator>& pair)
+ { return str.startsWith(pair.first); });
+ if(it == m_arithmeticOperation.end())
+ return false;
+
+ op= it->second;
+ str= str.remove(0, it->first.size());
+ return true;
+}
+
+bool ParsingToolBox::readLogicOperator(QString& str, Dice::CompareOperator& op)
+{
+ QString longKey;
+ auto const& keys= m_logicOp.keys();
+ for(const QString& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_logicOp.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+QString ParsingToolBox::getComment() const
+{
+ return m_comment;
+}
+
+void ParsingToolBox::setComment(const QString& comment)
+{
+ m_comment= comment;
+}
+const QMap<Dice::ERROR_CODE, QString>& ParsingToolBox::getErrorList() const
+{
+ return m_errorMap;
+}
+const QMap<Dice::ERROR_CODE, QString>& ParsingToolBox::getWarningList() const
+{
+ return m_warningMap;
+}
+bool ParsingToolBox::readOperand(QString& str, ExecutionNode*& node)
+{
+ qint64 intValue= 1;
+ QString resultStr;
+ if(readDynamicVariable(str, intValue))
+ {
+ VariableNode* variableNode= new VariableNode();
+ variableNode->setIndex(static_cast<quint64>(intValue - 1));
+ variableNode->setData(&m_startNodes);
+ node= variableNode;
+ return true;
+ }
+ else if(readNumber(str, intValue))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(intValue);
+ node= numberNode;
+ return true;
+ }
+ else if(readString(str, resultStr))
+ {
+ StringNode* strNode= new StringNode();
+ strNode->setString(resultStr);
+ node= strNode;
+ return true;
+ }
+ return false;
+}
+
+Validator* ParsingToolBox::readValidator(QString& str, bool hasSquare)
+{
+ Validator* returnVal= nullptr;
+ auto opCompare= readConditionType(str);
+ Dice::CompareOperator myLogicOp{Dice::CompareOperator::Equal};
+ readLogicOperator(str, myLogicOp);
+
+ Dice::ConditionOperator condiOp{Dice::ConditionOperator::Modulo};
+ bool hasDiceLogicOperator= readDiceLogicOperator(str, condiOp);
+ ExecutionNode* operandNode= nullptr;
+ if(hasDiceLogicOperator)
+ {
+ if(readOperand(str, operandNode))
+ {
+ OperationCondition* condition= new OperationCondition();
+ condition->setConditionType(opCompare);
+ condition->setValueNode(operandNode);
+ Validator* valid= readValidator(str, hasSquare);
+ BooleanCondition* boolC= dynamic_cast<BooleanCondition*>(valid);
+ if(nullptr != boolC)
+ {
+ condition->setBoolean(boolC);
+ returnVal= condition;
+ }
+ else
+ {
+ delete condition;
+ }
+ }
+ }
+ else if(readOperand(str, operandNode))
+ {
+ bool isRange= false;
+ if(str.startsWith("..") && hasSquare)
+ {
+ str= str.remove(0, 2);
+ qint64 end= 0;
+ if(readNumber(str, end))
+ {
+ str= str.remove(0, 1);
+ qint64 start= operandNode->getScalarResult();
+ Range* range= new Range();
+ range->setConditionType(opCompare);
+ range->setValue(start, end);
+ returnVal= range;
+ isRange= true;
+ }
+ }
+
+ if(!isRange)
+ {
+ BooleanCondition* condition= new BooleanCondition();
+ condition->setConditionType(opCompare);
+ condition->setValueNode(operandNode);
+ condition->setOperator(myLogicOp);
+ returnVal= condition;
+ }
+ }
+ return returnVal;
+}
+
+Dice::ConditionType ParsingToolBox::readConditionType(QString& str)
+{
+ Dice::ConditionType type= Dice::OnEach;
+ if(str.startsWith('.'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OneOfThem;
+ }
+ else if(str.startsWith('?'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OnEachValue;
+ }
+ else if(str.startsWith('*'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::AllOfThem;
+ }
+ else if(str.startsWith(':'))
+ {
+ str= str.remove(0, 1);
+ type= Dice::OnScalar;
+ }
+ return type;
+}
+bool ParsingToolBox::hasError() const
+{
+ return !m_errorMap.isEmpty();
+}
+ValidatorList* ParsingToolBox::readValidatorList(QString& str)
+{
+ bool expectSquareBrasket= false;
+ if((str.startsWith("[")))
+ {
+ str= str.remove(0, 1);
+ expectSquareBrasket= true;
+ }
+ Validator* tmp= readValidator(str, expectSquareBrasket);
+ Dice::LogicOperation opLogic;
+
+ QVector<Dice::LogicOperation> operators;
+ QList<Validator*> validatorList;
+
+ while(nullptr != tmp)
+ {
+ bool hasOperator= readLogicOperation(str, opLogic);
+ if(hasOperator)
+ {
+ operators.append(opLogic);
+ validatorList.append(tmp);
+ tmp= readValidator(str, expectSquareBrasket);
+ }
+ else
+ {
+ if((expectSquareBrasket) && (str.startsWith("]")))
+ {
+ str= str.remove(0, 1);
+ // isOk=true;
+ }
+ validatorList.append(tmp);
+ tmp= nullptr;
+ }
+ }
+ if(!validatorList.isEmpty())
+ {
+ ValidatorList* validator= new ValidatorList();
+ validator->setOperationList(operators);
+ validator->setValidators(validatorList);
+ return validator;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+bool ParsingToolBox::readLogicOperation(QString& str, Dice::LogicOperation& op)
+{
+ QString longKey;
+ auto const& keys= m_logicOperation.keys();
+ for(auto& tmp : keys)
+ {
+ if(str.startsWith(tmp))
+ {
+ if(longKey.size() < tmp.size())
+ {
+ longKey= tmp;
+ }
+ }
+ }
+ if(longKey.size() > 0)
+ {
+ str= str.remove(0, longKey.size());
+ op= m_logicOperation.value(longKey);
+ return true;
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readNumber(QString& str, qint64& myNumber)
+{
+ if(str.isEmpty())
+ return false;
+
+ QString number;
+ int i= 0;
+ while(i < str.length() && ((str[i].isNumber()) || ((i == 0) && (str[i] == '-'))))
+ {
+ number+= str[i];
+ ++i;
+ }
+
+ if(number.isEmpty())
+ {
+ QString reason;
+ return readVariable(str, myNumber, reason);
+ }
+
+ bool ok;
+ myNumber= number.toLongLong(&ok);
+ if(ok)
+ {
+ str= str.remove(0, number.size());
+ return true;
+ }
+
+ return false;
+}
+bool ParsingToolBox::readDynamicVariable(QString& str, qint64& index)
+{
+ if(str.isEmpty())
+ return false;
+ if(str.startsWith('$'))
+ {
+ QString number;
+ int i= 1;
+ while(i < str.length() && (str[i].isNumber()))
+ {
+ number+= str[i];
+ ++i;
+ }
+
+ bool ok;
+ index= number.toLongLong(&ok);
+ if(ok)
+ {
+ str= str.remove(0, number.size() + 1);
+ return true;
+ }
+ }
+ return false;
+}
+
+ExecutionNode* ParsingToolBox::getLeafNode(ExecutionNode* start)
+{
+ if(nullptr == start)
+ return nullptr;
+
+ ExecutionNode* next= start;
+ while(nullptr != next->getNextNode())
+ {
+ next= next->getNextNode();
+ }
+ return next;
+}
+
+const std::vector<ExecutionNode*>& ParsingToolBox::getStartNodes()
+{
+ return m_startNodes;
+}
+
+QStringList ParsingToolBox::allFirstResultAsString(bool& hasAlias) const
+{
+ // QStringList allResult;
+ QStringList stringListResult;
+ for(auto node : m_startNodes)
+ {
+ QVariant var;
+ auto stringPair= hasResultOfType(Dice::RESULT_TYPE::STRING, node);
+ auto scalarPair= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node);
+ if(stringPair.first)
+ {
+ stringListResult << stringPair.second.toString();
+ hasAlias= true;
+ }
+ else if(scalarPair.first)
+ {
+ stringListResult << number(scalarPair.second.toReal());
+ hasAlias= true;
+ }
+ }
+ return stringListResult;
+}
+std::pair<bool, QVariant> ParsingToolBox::hasResultOfType(Dice::RESULT_TYPE type, ExecutionNode* node,
+ bool notthelast) const
+{
+ bool hasValidResult= false;
+ QVariant var;
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ while((result != nullptr) && (!hasValidResult))
+ {
+ bool lastResult= false;
+ if(notthelast)
+ lastResult= (nullptr == result->getPrevious());
+
+ if(result->hasResultOfType(type) && !lastResult)
+ {
+ hasValidResult= true;
+ var= result->getResult(type);
+ }
+ result= result->getPrevious();
+ }
+ return {hasValidResult, var};
+}
+
+QList<qreal> ParsingToolBox::scalarResultsFromEachInstruction() const
+{
+ QList<qreal> resultValues;
+ std::set<QString> alreadyVisitedNode;
+ for(auto node : m_startNodes)
+ {
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ bool scalarDone= false;
+ while((result != nullptr) && (!scalarDone))
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::SCALAR))
+ {
+ if(alreadyVisitedNode.find(result->getId()) == alreadyVisitedNode.end())
+ {
+ resultValues << result->getResult(Dice::RESULT_TYPE::SCALAR).toReal();
+ alreadyVisitedNode.insert(result->getId());
+ }
+ scalarDone= true;
+ }
+ result= result->getPrevious();
+ }
+ }
+ return resultValues;
+}
+
+QList<qreal> ParsingToolBox::sumOfDiceResult() const
+{
+ QList<qreal> resultValues;
+ for(auto node : m_startNodes)
+ {
+ qreal resultValue= 0;
+ ExecutionNode* next= ParsingToolBox::getLeafNode(node);
+ Result* result= next->getResult();
+ bool found= false;
+ while((nullptr != result) && (!found))
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* myDiceResult= dynamic_cast<DiceResult*>(result);
+ if(nullptr != myDiceResult)
+ {
+ for(auto& die : myDiceResult->getResultList())
+ {
+ resultValue+= die->getValue();
+ }
+ found= true;
+ }
+ }
+ result= result->getPrevious();
+ }
+ resultValues << resultValue;
+ }
+ return resultValues;
+}
+
+std::pair<QString, QString> ParsingToolBox::finalScalarResult() const
+{
+ QString scalarText;
+ QString lastScalarText;
+ auto listDie= diceResultFromEachInstruction();
+ if(hasIntegerResultNotInFirst())
+ {
+ QStringList strLst;
+ auto listScalar= scalarResultsFromEachInstruction();
+ for(auto val : listScalar)
+ {
+ strLst << number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+ lastScalarText= strLst.last();
+ }
+ else if(!listDie.isEmpty())
+ {
+ auto values= sumOfDiceResult();
+ QStringList strLst;
+ for(auto val : values)
+ {
+ strLst << number(val);
+ }
+ scalarText= QString("%1").arg(strLst.join(','));
+ }
+ return {scalarText, lastScalarText};
+}
+
+bool ParsingToolBox::hasIntegerResultNotInFirst() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::SCALAR, node, true).first;
+ }
+ return result;
+}
+
+bool ParsingToolBox::hasDiceResult() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::DICE_LIST, node).first;
+ }
+ return result;
+}
+bool ParsingToolBox::hasStringResult() const
+{
+ bool result= false;
+ for(auto node : m_startNodes)
+ {
+ result|= hasResultOfType(Dice::RESULT_TYPE::STRING, node).first;
+ }
+ return result;
+}
+
+QList<ExportedDiceResult> ParsingToolBox::diceResultFromEachInstruction() const
+{
+ QList<ExportedDiceResult> resultList;
+ for(auto start : m_startNodes)
+ {
+ resultList.append(ParsingToolBox::finalDiceResultFromInstruction(start));
+ }
+ return resultList;
+}
+
+QStringList listOfDiceResult(const QList<ExportedDiceResult>& list, bool removeDouble= false)
+{
+ QStringList listOfDiceResult;
+ std::set<QString> alreadyAdded;
+ for(auto map : list)
+ {
+ for(auto key : map.keys())
+ {
+ auto listOfList= map.value(key);
+ for(auto dice : listOfList)
+ {
+ QString stringVal;
+ for(auto val : dice)
+ {
+ if(removeDouble && (alreadyAdded.end() != alreadyAdded.find(val.uuid())))
+ continue;
+
+ alreadyAdded.insert(val.uuid());
+
+ qint64 total= 0;
+ QStringList dicelist;
+ for(auto score : val.result())
+ {
+ total+= score;
+ dicelist << QString::number(score);
+ }
+ if(val.result().size() > 1)
+ {
+ stringVal= QString("%1 [%2]").arg(total).arg(dicelist.join(','));
+ listOfDiceResult << stringVal;
+ }
+ else
+ {
+ listOfDiceResult << QString::number(total);
+ }
+ }
+ }
+ }
+ }
+ return listOfDiceResult;
+}
+
+QString ParsingToolBox::finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize,
+ bool removeUnhighlighted) const
+{
+ bool ok;
+ QStringList allStringlist= allFirstResultAsString(ok);
+ auto listFull= diceResultFromEachInstruction();
+
+ QStringList resultWithPlaceHolder;
+ std::for_each(allStringlist.begin(), allStringlist.end(),
+ [&resultWithPlaceHolder](const QString& sub)
+ {
+ QRegularExpression ex("%[1-3]?|\\$[1-9]+|@[1-9]+");
+ if(sub.contains(ex))
+ resultWithPlaceHolder.append(sub);
+ });
+ auto stringResult= resultWithPlaceHolder.isEmpty() ? allStringlist.join(",") : resultWithPlaceHolder.join(",");
+
+ auto pairScalar= finalScalarResult();
+
+ stringResult.replace("%1", pairScalar.first);
+ stringResult.replace("%2", listOfDiceResult(diceResultFromEachInstruction(), true).join(",").trimmed());
+ stringResult.replace("%3", pairScalar.second);
+ stringResult.replace("\\n", "\n");
+
+ QMap<Dice::ERROR_CODE, QString> errorMap;
+ stringResult= ParsingToolBox::replaceVariableToValue(stringResult, allStringlist, errorMap);
+ stringResult= ParsingToolBox::replacePlaceHolderToValue(stringResult, listFull, removeUnhighlighted, colorize);
+
+ return stringResult;
+}
+
+bool ParsingToolBox::readString(QString& str, QString& strResult)
+{
+ if(str.isEmpty())
+ return false;
+
+ if(str.startsWith('"'))
+ {
+ str= str.remove(0, 1);
+
+ int i= 0;
+ int j= 0;
+ bool previousEscape= false;
+ QString result;
+ /*&&
+ (((!previousEscape) && !(str[i]=='"')) || (previousEscape) && !(str[i]=='"'))
+ || (str[i]=='\\'))*/
+ while(i < str.length() && (!(!previousEscape && (str[i] == '"')) || (previousEscape && str[i] != '"')))
+ {
+ if(str[i] == '\\')
+ {
+ previousEscape= true;
+ }
+ else
+ {
+ if(previousEscape && str[i] != '\"')
+ {
+ result+= '\\';
+ ++j;
+ }
+ result+= str[i];
+ previousEscape= false;
+ }
+ ++i;
+ }
+
+ if(!result.isEmpty())
+ {
+ str= str.remove(0, i);
+ strResult= result;
+ if(str.startsWith('"'))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ParsingToolBox::readVariable(QString& str, qint64& myNumber, QString& reasonFail)
+{
+ if(str.isEmpty())
+ return false;
+
+ if(str.startsWith("${"))
+ {
+ str= str.remove(0, 2);
+ }
+ QString key;
+ int post= str.indexOf('}');
+ key= str.left(post);
+
+ if(!m_variableHash.isEmpty())
+ {
+ if(m_variableHash.contains(key))
+ {
+ QString value= m_variableHash.value(key);
+ bool ok;
+ int valueInt= value.toInt(&ok);
+ if(ok)
+ {
+ myNumber= valueInt;
+ str= str.remove(0, post + 1);
+ return true;
+ }
+ else
+ {
+ reasonFail= QStringLiteral("Variable value is %1, not a number").arg(value);
+ }
+ }
+ else
+ {
+ reasonFail= QStringLiteral("Variable not found");
+ }
+ }
+ else
+ {
+ reasonFail= QStringLiteral("No Variables are defined");
+ }
+
+ return false;
+}
+bool ParsingToolBox::readComma(QString& str)
+{
+ if(str.startsWith(","))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+bool ParsingToolBox::readOpenParentheses(QString& str)
+{
+ if(str.startsWith("("))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool ParsingToolBox::readCloseParentheses(QString& str)
+{
+ if(str.startsWith(")"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ else
+ return false;
+}
+
+int ParsingToolBox::findClosingCharacterIndexOf(QChar open, QChar closing, const QString& str, int offset)
+{
+ int counter= offset;
+ int i= 0;
+ for(auto const& letter : str)
+ {
+ if(letter == open)
+ ++counter;
+ else if(letter == closing)
+ --counter;
+
+ if(counter == 0)
+ return i;
+
+ ++i;
+ }
+ return -1;
+}
+
+bool ParsingToolBox::readList(QString& str, QStringList& list, QList<Range>& ranges)
+{
+ if(str.startsWith("["))
+ {
+ str= str.remove(0, 1);
+ int pos= findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]");
+ if(-1 != pos)
+ {
+ QString liststr= str.left(pos);
+ list= liststr.split(",");
+ str= str.remove(0, pos + 1);
+ readProbability(list, ranges);
+ return true;
+ }
+ }
+ return false;
+}
+bool ParsingToolBox::readAscending(QString& str)
+{
+ if(str.isEmpty())
+ {
+ return false;
+ }
+ else if(str.at(0) == 'l')
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readStopAtFirst(QString& str)
+{
+ if(str.isEmpty())
+ return false;
+ else if(str.at(0) == '^')
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+
+Dice::CONDITION_STATE ParsingToolBox::isValidValidator(ExecutionNode* previous, ValidatorList* val)
+{
+ DiceRollerNode* node= getDiceRollerNode(previous);
+ if(nullptr == node)
+ return Dice::CONDITION_STATE::ERROR_STATE;
+
+ return val->isValidRangeSize(node->getRange());
+}
+DiceRollerNode* ParsingToolBox::getDiceRollerNode(ExecutionNode* previous)
+{
+ while(nullptr != previous)
+ {
+ DiceRollerNode* node= dynamic_cast<DiceRollerNode*>(previous);
+ if(nullptr != node)
+ {
+ return node;
+ }
+ previous= previous->getPreviousNode();
+ }
+ return nullptr;
+}
+bool ParsingToolBox::readDiceRange(QString& str, qint64& start, qint64& end)
+{
+ bool expectSquareBrasket= false;
+
+ if((str.startsWith("[")))
+ {
+ str= str.remove(0, 1);
+ expectSquareBrasket= true;
+ }
+ if(readNumber(str, start))
+ {
+ if(str.startsWith(".."))
+ {
+ str= str.remove(0, 2);
+ if(readNumber(str, end))
+ {
+ if(expectSquareBrasket)
+ {
+ if(str.startsWith("]"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ }
+ else if(expectSquareBrasket)
+ {
+ if(str.startsWith("]"))
+ {
+ str= str.remove(0, 1);
+ end= start;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+ParsingToolBox::LIST_OPERATOR ParsingToolBox::readListOperator(QString& str)
+{
+ QHash<QChar, ParsingToolBox::LIST_OPERATOR> hash;
+ hash.insert('u', UNIQUE);
+ hash.insert('n', NOCOMMA);
+ bool findOne= false;
+ ParsingToolBox::LIST_OPERATOR op= NONE;
+ int i= 0;
+ do
+ {
+ auto keys= hash.keys();
+ findOne= false;
+ for(auto const& key : qAsConst(keys))
+ {
+ if(str.startsWith(key))
+ {
+ str= str.remove(0, 1);
+ op= hash[key];
+ findOne= true;
+ ++i;
+ }
+ }
+ } while(findOne);
+
+ return i > 1 ? UniqueAndNoComma : op;
+}
+
+bool ParsingToolBox::readPainterParameter(PainterNode* painter, QString& str)
+{
+ if(!str.startsWith('['))
+ return false;
+
+ str= str.remove(0, 1);
+ int pos= str.indexOf(']');
+
+ if(pos == -1)
+ return false;
+
+ QString data= str.left(pos);
+ str= str.remove(0, pos + 1);
+ QStringList duos= data.split(',');
+ bool result= false;
+ for(QString& duoStr : duos)
+ {
+ QStringList keyValu= duoStr.split(':');
+ if(keyValu.size() == 2)
+ {
+ painter->insertColorItem(keyValu[1], keyValu[0].toInt());
+ result= true;
+ }
+ }
+
+ return result;
+}
+
+QHash<QString, QString> ParsingToolBox::getVariableHash()
+{
+ return m_variableHash;
+}
+
+void ParsingToolBox::setVariableHash(const QHash<QString, QString>& variableHash)
+{
+ m_variableHash= variableHash;
+}
+
+void ParsingToolBox::setStartNodes(std::vector<ExecutionNode*> nodes)
+{
+ m_startNodes= nodes;
+}
+
+void ParsingToolBox::readProbability(QStringList& str, QList<Range>& ranges)
+{
+ quint64 totalDistance= 0;
+ quint64 undefDistance= 0;
+ int undefCount= 0;
+ int maxValue= 0;
+ int i= 0;
+ int j= 0;
+ bool hasPercentage= false;
+ for(QString line : str)
+ {
+ int pos= line.indexOf('[');
+ if(-1 != pos)
+ {
+ QString rangeStr= line.right(line.length() - pos);
+ line= line.left(pos);
+ str[j]= line;
+ qint64 start= 0;
+ qint64 end= 0;
+ if(readDiceRange(rangeStr, start, end))
+ {
+ Range range;
+ range.setValue(start, end);
+ ranges.append(range);
+ totalDistance+= static_cast<quint64>(end - start + 1);
+ ++i;
+ }
+ else // percentage
+ {
+ hasPercentage= true;
+ Range range;
+ range.setStart(start);
+ ranges.append(range);
+ ++undefCount;
+ undefDistance+= static_cast<quint64>(start);
+ }
+ if((end > maxValue) || (i == 1))
+ {
+ maxValue= static_cast<int>(end);
+ }
+ }
+ else
+ {
+ Range range;
+ range.setEmptyRange(true);
+ ranges.append(range);
+ }
+ ++j;
+ }
+
+ if((hasPercentage) && (undefDistance != 0))
+ {
+ qreal ratio= 100.0 / static_cast<qreal>(undefDistance);
+ qint64 realStart= 0;
+ for(int i= 0; i < ranges.size(); ++i)
+ {
+ Range tmp= ranges.at(i);
+ if(!tmp.isFullyDefined())
+ {
+ int dist= static_cast<int>(tmp.getStart());
+ tmp.setStart(realStart + 1);
+ double truc= dist * ratio;
+
+ tmp.setEnd(static_cast<int>(realStart + truc));
+ realStart= tmp.getEnd();
+ ranges[i]= tmp;
+ }
+ }
+ }
+ else
+ {
+ int limitUp= 1;
+ for(int i= 0; i < ranges.size(); ++i)
+ {
+ Range range= ranges.at(i);
+ if(range.isEmptyRange())
+ {
+ range.setStart(limitUp);
+ range.setEnd(limitUp);
+ range.setEmptyRange(false);
+ }
+ else
+ {
+ qint64 sizeRange= range.getEnd() - range.getStart();
+ range.setStart(limitUp);
+ limitUp+= sizeRange;
+ range.setEnd(limitUp);
+ }
+ ++limitUp;
+ ranges[i]= range;
+ }
+ }
+}
+bool ParsingToolBox::readComment(QString& str, QString& result, QString& comment)
+{
+ QString left= str;
+ str= str.trimmed();
+ if(str.startsWith("#"))
+ {
+ comment= left;
+ str= str.remove(0, 1);
+ result= str.trimmed();
+ str= "";
+ return true;
+ }
+ return false;
+}
+
+QString ParsingToolBox::replaceVariableToValue(const QString& source, QStringList values,
+ QMap<Dice::ERROR_CODE, QString>& errorMap)
+{
+ QString result= source;
+
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readVariableFromString(source, start);
+ if(ref.resultIndex() > values.size())
+ {
+ auto error= QString("No valid value at index: $%1").arg(ref.resultIndex());
+ errorMap.insert(Dice::ERROR_CODE::INVALID_INDEX, error);
+ return error;
+ }
+
+ valid= ref.isValid();
+ if(!valid)
+ continue;
+
+ result.remove(ref.position(), ref.length());
+ auto val= values[ref.resultIndex() - 1];
+
+ if(ref.subIndex() >= 0)
+ {
+ auto valSplit= val.split(",");
+ if(ref.subIndex() < valSplit.size())
+ val= valSplit[ref.subIndex()];
+ }
+
+ if(ref.digitNumber() != 0)
+ {
+ auto realVal= QString("%1").arg(val, ref.digitNumber(), QChar('0'));
+ result.insert(ref.position(), realVal);
+ }
+ else
+ {
+ result.insert(ref.position(), val);
+ }
+ } while(valid);
+
+ return result;
+}
+
+QString ParsingToolBox::replacePlaceHolderFromJson(const QString& source, const QJsonObject& obj)
+{
+ QStringList resultList;
+ auto instructions= obj["instructions"].toArray();
+ std::vector<std::vector<std::pair<int, QList<QStringList>>>> instructionResult;
+ for(auto inst : qAsConst(instructions))
+ {
+ std::vector<std::pair<int, QList<QStringList>>> map;
+ auto obj= inst.toObject();
+ auto vals= obj["diceval"].toArray();
+ int lastFace= -1;
+ for(auto const& valRef : qAsConst(vals))
+ {
+ auto diceObj= valRef.toObject();
+ auto face= diceObj["face"].toInt();
+ auto it= std::find_if(std::begin(map), std::end(map),
+ [face](const std::pair<int, QList<QStringList>>& val) { return val.first == face; });
+
+ auto realVal= diceObj["string"].toString();
+ if(lastFace == -1 || lastFace != face)
+ {
+ QList<QStringList> listOfList;
+ listOfList << (QStringList() << realVal);
+ map.push_back({face, listOfList});
+ }
+ else if(lastFace == face)
+ {
+ auto& valList= it->second.last();
+ valList.append(realVal);
+ }
+ lastFace= face;
+ }
+ instructionResult.push_back(map);
+ }
+ std::transform(std::begin(instructionResult), std::end(instructionResult), std::back_inserter(resultList),
+ [](const std::vector<std::pair<int, QList<QStringList>>>& map)
+ {
+ QStringList valuesStr;
+ auto multiKey= (map.size() > 1);
+ for(auto item : map)
+ {
+ auto face= item.first;
+ auto valueList= item.second;
+ QStringList strs;
+ for(auto list : valueList)
+ {
+ strs << list.join(",");
+ }
+ if(!multiKey)
+ valuesStr << strs.join(",");
+ else
+ valuesStr << QString("d%1:(%2)").arg(face).arg(strs.join(","));
+ }
+ return valuesStr.join(" - ");
+ });
+
+ QString result= source;
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readPlaceHolderFromString(source, start);
+ if(ref.isValid())
+ {
+ result.remove(ref.position(), ref.length());
+ auto val= resultList[ref.resultIndex() - 1];
+ result.insert(ref.position(), val);
+ }
+ else
+ {
+ valid= false;
+ }
+ } while(valid);
+
+ return result;
+}
+
+QString ParsingToolBox::replacePlaceHolderToValue(const QString& source, const QList<ExportedDiceResult>& list,
+ bool removeUnhighlighted,
+ std::function<QString(const QString&, const QString&, bool)> colorize)
+{
+ QStringList resultList;
+ std::transform(
+ std::begin(list), std::end(list), std::back_inserter(resultList),
+ [removeUnhighlighted, colorize](const ExportedDiceResult& dice)
+ {
+ QStringList valuesStr;
+ if(dice.size() == 1)
+ {
+ auto values= dice.values();
+ std::transform(
+ std::begin(values), std::end(values), std::back_inserter(valuesStr),
+ [removeUnhighlighted, colorize](const QList<ListDiceResult>& dice)
+ {
+ QStringList textList;
+ std::transform(
+ std::begin(dice), std::end(dice), std::back_inserter(textList),
+ [removeUnhighlighted, colorize](const ListDiceResult& dice)
+ {
+ QStringList list;
+ ListDiceResult values= dice;
+ if(removeUnhighlighted)
+ {
+ values.clear();
+ std::copy_if(std::begin(dice), std::end(dice), std::back_inserter(values),
+ [](const HighLightDice& hl) { return hl.isHighlighted(); });
+ }
+
+ std::transform(std::begin(values), std::end(values), std::back_inserter(list),
+ [colorize](const HighLightDice& hl)
+ { return colorize(hl.getResultString(), {}, hl.isHighlighted()); });
+ return list.join(",");
+ });
+ textList.removeAll(QString());
+ return textList.join(",");
+ });
+ }
+ else if(dice.size() > 1)
+ {
+ for(auto key : dice.keys())
+ {
+ auto list= dice.value(key);
+ for(auto values : list)
+ {
+ QStringList textVals;
+ std::transform(std::begin(values), std::end(values), std::back_inserter(textVals),
+ [](const HighLightDice& dice) { return dice.getResultString(); });
+ valuesStr.append(QString("d%1 [%2]").arg(key).arg(textVals.join(",")));
+ }
+ }
+ }
+ return valuesStr.join(",");
+ });
+
+ QString result= source;
+ int start= source.size() - 1;
+ bool valid= true;
+ do
+ {
+ auto ref= readPlaceHolderFromString(source, start);
+ if(ref.isValid())
+ {
+ result.remove(ref.position(), ref.length());
+ auto val= resultList[ref.resultIndex() - 1];
+ result.insert(ref.position(), val);
+ }
+ else
+ {
+ valid= false;
+ }
+ } while(valid);
+
+ return result;
+}
+void ParsingToolBox::readSubtitutionParameters(SubtituteInfo& info, QString& rest)
+{
+ auto sizeS= rest.size();
+ if(rest.startsWith("{"))
+ {
+ rest= rest.remove(0, 1);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ if(rest.startsWith("}"))
+ {
+ rest= rest.remove(0, 1);
+ info.setDigitNumber(static_cast<int>(number));
+ }
+ }
+ }
+ if(rest.startsWith("["))
+ {
+ rest= rest.remove(0, 1);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ if(rest.startsWith("]"))
+ {
+ rest= rest.remove(0, 1);
+ info.setSubIndex(static_cast<int>(number));
+ }
+ }
+ }
+ info.setLength(info.length() + sizeS - rest.size());
+}
+
+bool ParsingToolBox::readReaperArguments(RepeaterNode* node, QString& source)
+{
+ if(!readOpenParentheses(source))
+ return false;
+
+ auto instructions= readInstructionList(source, false);
+ if(instructions.empty())
+ return false;
+
+ readComma(source);
+ ExecutionNode* tmp;
+ if(readOperand(source, tmp))
+ {
+ if(source.startsWith("+"))
+ {
+ node->setSumAll(true);
+ source= source.remove(0, 1);
+ }
+ if(readCloseParentheses(source))
+ {
+ node->setCommand(instructions);
+ node->setTimeNode(tmp);
+ return true;
+ }
+ }
+
+ return false;
+}
+bool ParsingToolBox::readExpression(QString& str, ExecutionNode*& node)
+{
+ ExecutionNode* operandNode= nullptr;
+ if(readOpenParentheses(str))
+ {
+ ExecutionNode* internalNode= nullptr;
+ if(readExpression(str, internalNode))
+ {
+ ParenthesesNode* parentheseNode= new ParenthesesNode();
+ parentheseNode->setInternelNode(internalNode);
+ node= parentheseNode;
+ if(readCloseParentheses(str))
+ {
+ ExecutionNode* diceNode= nullptr;
+ ExecutionNode* operatorNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ parentheseNode->setNextNode(diceNode);
+ }
+ else if(readExpression(str, operatorNode))
+ {
+ parentheseNode->setNextNode(operatorNode);
+ }
+ return true;
+ }
+ else
+ {
+ m_warningMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Expected closing parenthesis - can't validate the inside."));
+ }
+ }
+ }
+ else if(readFunction(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOptionFromNull(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOperatorFromNull(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readOperand(str, operandNode))
+ {
+ ExecutionNode* diceNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ operandNode->setNextNode(diceNode);
+ }
+ node= operandNode;
+
+ operandNode= ParsingToolBox::getLeafNode(operandNode);
+ // ExecutionNode* operatorNode=nullptr;
+ while(readOperator(str, operandNode))
+ {
+ // operandNode->setNextNode(operatorNode);
+ operandNode= ParsingToolBox::getLeafNode(operandNode);
+ }
+ return true;
+ }
+ else if(readCommand(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readNode(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else if(readValuesList(str, operandNode))
+ {
+ node= operandNode;
+ return true;
+ }
+ else
+ {
+ ExecutionNode* diceNode= nullptr;
+ if(readDice(str, diceNode))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(1);
+ numberNode->setNextNode(diceNode);
+ node= numberNode;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return false;
+}
+
+bool ParsingToolBox::readValuesList(QString& str, ExecutionNode*& node)
+{
+ if(!str.startsWith("["))
+ return false;
+
+ str= str.remove(0, 1);
+ int pos= ParsingToolBox::findClosingCharacterIndexOf('[', ']', str, 1); // str.indexOf("]");
+ if(-1 == pos)
+ return false;
+
+ QString liststr= str.left(pos);
+ auto list= liststr.split(",");
+ str= str.remove(0, pos + 1);
+ auto values= new ValuesListNode();
+ for(auto var : qAsConst(list))
+ {
+ qint64 number= 1;
+ var= var.trimmed();
+ if(ParsingToolBox::readDynamicVariable(var, number))
+ {
+ VariableNode* variableNode= new VariableNode();
+ variableNode->setIndex(static_cast<quint64>(number - 1));
+ variableNode->setData(&m_startNodes);
+ values->insertValue(variableNode);
+ }
+ else if(ParsingToolBox::readNumber(var, number))
+ {
+ NumberNode* numberNode= new NumberNode();
+ numberNode->setNumber(number);
+ values->insertValue(numberNode);
+ }
+ }
+ node= values;
+ return true;
+}
+bool ParsingToolBox::readOptionFromNull(QString& str, ExecutionNode*& node)
+{
+ StartingNode nodePrevious;
+ if(readOption(str, &nodePrevious))
+ {
+ auto nodeNext= nodePrevious.getNextNode();
+ nodePrevious.setNextNode(nullptr);
+ node= nodeNext;
+ return true;
+ }
+ return false;
+}
+
+void ParsingToolBox::setHelpPath(const QString& path)
+{
+ m_helpPath= path;
+}
+
+bool ParsingToolBox::readOperatorFromNull(QString& str, ExecutionNode*& node)
+{
+ StartingNode nodePrevious;
+ if(readOperator(str, &nodePrevious))
+ {
+ auto nodeNext= nodePrevious.getNextNode();
+ nodePrevious.setNextNode(nullptr);
+ node= nodeNext;
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readOption(QString& str, ExecutionNode* previous) //,
+{
+ if(str.isEmpty())
+ {
+ return false;
+ }
+
+ bool found= false;
+ auto keys= m_OptionOp.keys();
+ for(int i= 0; ((i < keys.size()) && (!found)); ++i)
+ {
+ QString key= keys.at(i);
+
+ if(str.startsWith(key))
+ {
+ str= str.remove(0, key.size());
+ auto operatorName= m_OptionOp.value(key);
+ switch(operatorName)
+ {
+ case Keep:
+ {
+ ExecutionNode* value= nullptr;
+ bool ascending= readAscending(str);
+
+ if(readOperand(str, value))
+ {
+ auto node= addSort(previous, ascending);
+ KeepDiceExecNode* nodeK= new KeepDiceExecNode();
+ nodeK->setDiceKeepNumber(value);
+ node->setNextNode(nodeK);
+ found= true;
+ }
+ }
+ break;
+ case KeepAndExplode:
+ {
+ bool ascending= readAscending(str);
+ ExecutionNode* value= nullptr;
+ if(readOperand(str, value))
+ {
+ DiceRollerNode* nodeTmp= dynamic_cast<DiceRollerNode*>(previous);
+ if(nullptr != nodeTmp)
+ {
+ previous= addExplodeDiceNode(static_cast<qint64>(nodeTmp->getFaces()), previous);
+ }
+
+ auto node= addSort(previous, ascending);
+
+ KeepDiceExecNode* nodeK= new KeepDiceExecNode();
+ nodeK->setDiceKeepNumber(value);
+
+ node->setNextNode(nodeK);
+ node= nodeK;
+ found= true;
+ }
+ }
+ break;
+ case Filter:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ auto validity= isValidValidator(previous, validatorList);
+
+ FilterNode* filterNode= new FilterNode();
+ filterNode->setValidatorList(validatorList);
+
+ previous->setNextNode(filterNode);
+ found= true;
+ }
+ }
+ break;
+ case Sort:
+ {
+ bool ascending= readAscending(str);
+ addSort(previous, ascending);
+ /*if(!hasDice)
+ {
+ m_errorMap.insert(ExecutionNode::BAD_SYNTAXE,QObject::tr("Sort Operator does not support default
+ dice. You should add dice command before the s"));
+ }*/
+ found= true;
+ }
+ break;
+ case Count:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ auto validity= isValidValidator(previous, validatorList);
+
+ CountExecuteNode* countNode= new CountExecuteNode();
+ countNode->setValidatorList(validatorList);
+
+ previous->setNextNode(countNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the c operator. Please, change it"));
+ }
+ }
+ break;
+ case Reroll:
+ case RerollUntil:
+ case RerollAndAdd:
+ // Todo: I think that Exploding and Rerolling could share the same code
+ {
+ auto validatorList= readValidatorList(str);
+ QString symbol= m_OptionOp.key(operatorName);
+ if(nullptr != validatorList)
+ {
+ switch(isValidValidator(previous, validatorList))
+ {
+ case Dice::CONDITION_STATE::ALWAYSTRUE:
+ if(operatorName == RerollAndAdd)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Validator is always true for the %1 operator. Please, change it")
+ .arg(symbol));
+ }
+ break;
+ case Dice::CONDITION_STATE::UNREACHABLE:
+ if(operatorName == RerollUntil)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("Condition can't be reached, causing endless loop. Please, "
+ "change the %1 option condition")
+ .arg(symbol));
+ }
+ break;
+ case Dice::CONDITION_STATE::ERROR_STATE:
+ default:
+ break;
+ }
+
+ auto reroll= (operatorName == RerollAndAdd || operatorName == Reroll);
+ auto addingMode= (operatorName == RerollAndAdd);
+ RerollDiceNode* rerollNode= new RerollDiceNode(reroll, addingMode);
+ ExecutionNode* nodeParam= nullptr;
+ if(readParameterNode(str, nodeParam))
+ {
+ rerollNode->setInstruction(nodeParam);
+ }
+ rerollNode->setValidatorList(validatorList);
+ previous->setNextNode(rerollNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the %1 operator. Please, change it").arg(symbol));
+ }
+ }
+ break;
+ case Explode:
+ {
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ if(Dice::CONDITION_STATE::ALWAYSTRUE == isValidValidator(previous, validatorList))
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::ENDLESS_LOOP_ERROR,
+ QObject::tr("This condition %1 introduces an endless loop. Please, change it")
+ .arg(validatorList->toString()));
+ }
+ ExplodeDiceNode* explodedNode= new ExplodeDiceNode();
+ explodedNode->setValidatorList(validatorList);
+ previous->setNextNode(explodedNode);
+ found= true;
+ }
+ else
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Validator is missing after the e operator. Please, change it"));
+ }
+ }
+ break;
+ case Merge:
+ {
+ MergeNode* mergeNode= new MergeNode();
+ mergeNode->setStartList(&m_startNodes);
+ previous->setNextNode(mergeNode);
+ found= true;
+ }
+ break;
+ case AllSameExplode:
+ {
+ AllSameNode* allSame= new AllSameNode();
+ previous->setNextNode(allSame);
+ found= true;
+ }
+ break;
+ case SwitchCaseOption:
+ {
+ auto scNode= new SwitchCaseNode();
+ found= readSwitchCaseNode(str, scNode);
+ previous->setNextNode(scNode);
+ }
+ break;
+ case TransformOption:
+ {
+ auto scNode= new ReplaceValueNode();
+ found= readReplaceValueNode(str, scNode);
+ previous->setNextNode(scNode);
+ }
+ break;
+ case Bind:
+ {
+ BindNode* bindNode= new BindNode();
+ bindNode->setStartList(&m_startNodes);
+ previous->setNextNode(bindNode);
+ found= true;
+ }
+ break;
+ case Occurences:
+ {
+ qint64 number= 0;
+ auto occNode= new OccurenceCountNode();
+ if(readNumber(str, number))
+ {
+ occNode->setWidth(number);
+ auto validatorList= readValidatorList(str);
+ if(validatorList)
+ {
+ occNode->setValidatorList(validatorList);
+ }
+ else if(readComma(str))
+ {
+ if(readNumber(str, number))
+ {
+ occNode->setHeight(number);
+ }
+ }
+ }
+ previous->setNextNode(occNode);
+ found= true;
+ }
+ break;
+ case Unique:
+ {
+ auto node= new UniqueNode();
+ previous->setNextNode(node);
+ found= true;
+ }
+ break;
+ case Painter:
+ {
+ PainterNode* painter= new PainterNode();
+ if(!readPainterParameter(painter, str))
+ {
+ m_errorMap.insert(Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Missing parameter for Painter node (p)"));
+ delete painter;
+ }
+ else
+ {
+ previous->setNextNode(painter);
+ found= true;
+ }
+ }
+ break;
+ case ifOperator:
+ {
+ IfNode* nodeif= new IfNode();
+ nodeif->setConditionType(readConditionType(str));
+ auto validatorList= readValidatorList(str);
+ if(nullptr != validatorList)
+ {
+ ExecutionNode* trueNode= nullptr;
+ ExecutionNode* falseNode= nullptr;
+ if(readIfInstruction(str, trueNode, falseNode))
+ {
+ nodeif->setInstructionTrue(trueNode);
+ nodeif->setInstructionFalse(falseNode);
+ nodeif->setValidatorList(validatorList);
+ previous->setNextNode(nodeif);
+ found= true;
+ }
+ else
+ {
+ delete nodeif;
+ }
+ }
+ else
+ {
+ delete nodeif;
+ }
+ break;
+ }
+ case Split:
+ {
+ SplitNode* splitnode= new SplitNode();
+ previous->setNextNode(splitnode);
+ found= true;
+ }
+ break;
+ case Group:
+ {
+ bool stringResult= readStringResultParameter(str);
+ qint64 groupNumber= 0;
+ if(readNumber(str, groupNumber))
+ {
+ GroupNode* groupNode= new GroupNode(stringResult);
+ groupNode->setGroupValue(groupNumber);
+ previous->setNextNode(groupNode);
+ found= true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return found;
+}
+bool ParsingToolBox::readStringResultParameter(QString& str)
+{
+ if(str.startsWith("s"))
+ {
+ str.remove(0, 1);
+ return true;
+ }
+ return false;
+}
+bool ParsingToolBox::readIfInstruction(QString& str, ExecutionNode*& trueNode, ExecutionNode*& falseNode)
+{
+ if(readBlocInstruction(str, trueNode))
+ {
+ if(readBlocInstruction(str, falseNode))
+ {
+ return true;
+ }
+ return true;
+ }
+ return false;
+}
+DiceRollerNode* ParsingToolBox::addRollDiceNode(qint64 faces, ExecutionNode* previous)
+{
+ DiceRollerNode* mydiceRoller= new DiceRollerNode(faces);
+ previous->setNextNode(mydiceRoller);
+ return mydiceRoller;
+}
+ExplodeDiceNode* ParsingToolBox::addExplodeDiceNode(qint64 value, ExecutionNode* previous)
+{
+ ExplodeDiceNode* explodeDiceNode= new ExplodeDiceNode();
+ NumberNode* node= new NumberNode();
+ node->setNumber(value);
+ BooleanCondition* condition= new BooleanCondition();
+ condition->setConditionType(Dice::OnEach);
+ condition->setValueNode(node);
+ condition->setOperator(Dice::CompareOperator::Equal);
+ auto valList= new ValidatorList();
+ valList->setValidators(QList<Validator*>() << condition);
+ auto validity= isValidValidator(previous, valList);
+ explodeDiceNode->setValidatorList(valList);
+ previous->setNextNode(explodeDiceNode);
+ return explodeDiceNode;
+}
+bool ParsingToolBox::readParameterNode(QString& str, ExecutionNode*& node)
+{
+ if(str.startsWith("("))
+ {
+ str= str.remove(0, 1);
+ if(readExpression(str, node))
+ {
+ if(str.startsWith(")"))
+ {
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool ParsingToolBox::readSwitchCaseNode(QString& str, SwitchCaseNode* node)
+{
+ bool res= false;
+ node->setStopAtFirt(ParsingToolBox::readStopAtFirst(str));
+ bool hasInstructionBloc= false;
+ do
+ {
+ auto validator= readValidatorList(str);
+ ExecutionNode* exeNode= nullptr;
+ hasInstructionBloc= readBlocInstruction(str, exeNode);
+ if(hasInstructionBloc)
+ {
+ node->insertCase(exeNode, validator);
+ res= true;
+ }
+
+ } while(hasInstructionBloc);
+
+ return res;
+}
+
+bool ParsingToolBox::readReplaceValueNode(QString& str, ReplaceValueNode* node)
+{
+ bool res= false;
+ bool hasInstructionBloc= false;
+ do
+ {
+ auto validator= readValidatorList(str);
+ ExecutionNode* exeNode= nullptr;
+ hasInstructionBloc= readBlocInstruction(str, exeNode);
+ if(hasInstructionBloc)
+ {
+ node->insertCase(exeNode, validator);
+ res= true;
+ }
+
+ } while(hasInstructionBloc);
+
+ return res;
+}
+
+bool ParsingToolBox::readBlocInstruction(QString& str, ExecutionNode*& resultnode)
+{
+ if(str.startsWith('{'))
+ {
+ str= str.remove(0, 1);
+ ExecutionNode* node= nullptr;
+ Dice::ArithmeticOperator op;
+ ScalarOperatorNode* scalarNode= nullptr;
+ if(readArithmeticOperator(str, op))
+ {
+ scalarNode= new ScalarOperatorNode();
+ scalarNode->setArithmeticOperator(op);
+ }
+ if(readExpression(str, node))
+ {
+ if(str.startsWith('}'))
+ {
+ if(nullptr == scalarNode)
+ {
+ resultnode= node;
+ }
+ else
+ {
+ resultnode= scalarNode;
+ scalarNode->setInternalNode(node);
+ }
+ str= str.remove(0, 1);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+bool ParsingToolBox::readDice(QString& str, ExecutionNode*& node)
+{
+ DiceOperator currentOperator;
+
+ if(readDiceOperator(str, currentOperator))
+ {
+ if(currentOperator == D)
+ {
+ qint64 max;
+ qint64 min;
+ bool unique= (ParsingToolBox::UNIQUE == readListOperator(str)) ? true : false;
+ Dice::ArithmeticOperator op;
+
+ bool hasOp= readArithmeticOperator(str, op);
+ if(readNumber(str, max))
+ {
+ if(max < 1)
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr("Dice with %1 face(s) does not exist. Please, put a value higher than 0").arg(max));
+ return false;
+ }
+ DiceRollerNode* drNode= new DiceRollerNode(max);
+ drNode->setUnique(unique);
+ if(hasOp)
+ {
+ drNode->setOperator(op);
+ }
+ node= drNode;
+ ExecutionNode* current= drNode;
+ while(readOption(str, current))
+ {
+ current= ParsingToolBox::getLeafNode(current);
+ }
+ return true;
+ }
+ else if(readDiceRange(str, min, max))
+ {
+ DiceRollerNode* drNode= new DiceRollerNode(max, min);
+ drNode->setUnique(unique);
+ if(hasOp)
+ {
+ drNode->setOperator(op);
+ }
+ node= drNode;
+ ExecutionNode* current= drNode;
+ while(readOption(str, current))
+ {
+ current= ParsingToolBox::getLeafNode(current);
+ }
+ return true;
+ }
+ }
+ else if(currentOperator == L)
+ {
+ QStringList list;
+ QList<Range> listRange;
+ ParsingToolBox::LIST_OPERATOR op= readListOperator(str);
+ if(readList(str, list, listRange))
+ {
+ ListSetRollNode* lsrNode= new ListSetRollNode();
+ lsrNode->setRangeList(listRange);
+ if(op == ParsingToolBox::UNIQUE || op == ParsingToolBox::UniqueAndNoComma)
+ {
+ lsrNode->setUnique(true);
+ }
+ if(op == ParsingToolBox::NOCOMMA || op == ParsingToolBox::UniqueAndNoComma)
+ {
+ lsrNode->setNoComma(true);
+ }
+ lsrNode->setListValue(list);
+ node= lsrNode;
+ return true;
+ }
+ else
+ {
+ m_errorMap.insert(
+ Dice::ERROR_CODE::BAD_SYNTAXE,
+ QObject::tr(
+ "List is missing after the L operator. Please, add it (e.g : 1L[sword,spear,gun,arrow])"));
+ }
+ }
+ }
+
+ return false;
+}
+bool ParsingToolBox::readDiceOperator(QString& str, DiceOperator& op)
+{
+ QStringList listKey= m_mapDiceOp.keys();
+ for(const QString& key : qAsConst(listKey))
+ {
+ if(str.startsWith(key, Qt::CaseInsensitive))
+ {
+ str= str.remove(0, key.size());
+ op= m_mapDiceOp.value(key);
+ return true;
+ }
+ }
+ return false;
+}
+QString ParsingToolBox::convertAlias(QString str)
+{
+ for(auto& cmd : m_aliasList)
+ {
+ if(cmd->isEnable())
+ {
+ cmd->resolved(str);
+ }
+ }
+ return str;
+}
+
+bool ParsingToolBox::readCommand(QString& str, ExecutionNode*& node)
+{
+ if(m_commandList.contains(str))
+ {
+ if(str == QLatin1String("help"))
+ {
+ str= str.remove(0, QLatin1String("help").size());
+ HelpNode* help= new HelpNode();
+ if(!m_helpPath.isEmpty())
+ {
+ help->setHelpPath(m_helpPath);
+ }
+ node= help;
+ }
+ else if(str == QLatin1String("la"))
+ {
+ str= str.remove(0, QLatin1String("la").size());
+ node= new ListAliasNode(m_aliasList);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readDiceExpression(QString& str, ExecutionNode*& node)
+{
+ bool returnVal= false;
+
+ ExecutionNode* next= nullptr;
+ if(readDice(str, next))
+ {
+ ExecutionNode* latest= next;
+ while(readOption(str, latest))
+ {
+ while(nullptr != latest->getNextNode())
+ {
+ latest= latest->getNextNode();
+ }
+ }
+
+ node= next;
+ returnVal= true;
+ }
+ else
+ {
+ returnVal= false;
+ }
+ return returnVal;
+}
+
+bool ParsingToolBox::readOperator(QString& str, ExecutionNode* previous)
+{
+ bool result= false;
+ if(str.isEmpty() || nullptr == previous)
+ {
+ return result;
+ }
+
+ Dice::ArithmeticOperator op;
+ if(readArithmeticOperator(str, op))
+ {
+ ScalarOperatorNode* node= new ScalarOperatorNode();
+ node->setArithmeticOperator(op);
+ ExecutionNode* nodeExec= nullptr;
+ if(readExpression(str, nodeExec))
+ {
+ node->setInternalNode(nodeExec);
+ if(nullptr == nodeExec)
+ {
+ delete node;
+ return result;
+ }
+ ExecutionNode* nodeExecOrChild= nodeExec;
+ ExecutionNode* parent= nullptr;
+
+ while((nullptr != nodeExecOrChild) && (node->getPriority() < nodeExecOrChild->getPriority()))
+ {
+ parent= nodeExecOrChild;
+ nodeExecOrChild= nodeExecOrChild->getNextNode();
+ }
+ // management of operator priority
+ if((nullptr != nodeExecOrChild) && (nodeExec != nodeExecOrChild))
+ {
+ // good 1 1 2 ; bad 1 0 4
+ if(nodeExecOrChild->getPriority() >= node->getPriority())
+ {
+ node->setNextNode(nodeExecOrChild);
+ parent->setNextNode(nullptr);
+ }
+ }
+ else if(node->getPriority() >= nodeExec->getPriority())
+ {
+ node->setNextNode(nodeExec->getNextNode());
+ nodeExec->setNextNode(nullptr);
+ }
+
+ // nodeResult = node;
+ previous->setNextNode(node);
+
+ result= true;
+ }
+ else
+ {
+ delete node;
+ }
+ }
+ else
+ {
+ while(readOption(str, previous))
+ {
+ previous= ParsingToolBox::getLeafNode(previous);
+ result= true;
+ }
+ }
+ return result;
+}
+bool ParsingToolBox::readFunction(QString& str, ExecutionNode*& node)
+{
+ for(const auto& kv : m_functionMap)
+ {
+ if(str.startsWith(kv.first))
+ {
+ str= str.remove(0, kv.first.size());
+ switch(kv.second)
+ {
+ case REPEAT:
+ {
+ auto repeaterNode= new RepeaterNode();
+ if(ParsingToolBox::readReaperArguments(repeaterNode, str))
+ {
+ node= repeaterNode;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if(node == nullptr)
+ return false;
+ return true;
+}
+
+bool ParsingToolBox::readNode(QString& str, ExecutionNode*& node)
+{
+ if(str.isEmpty())
+ return false;
+
+ QString key= str.at(0);
+ if(m_nodeActionMap.contains(key))
+ {
+ JumpBackwardNode* jumpNode= new JumpBackwardNode();
+ node= jumpNode;
+ str= str.remove(0, 1);
+ readOption(str, jumpNode);
+ return true;
+ }
+ return false;
+}
+
+bool ParsingToolBox::readInstructionOperator(QChar c)
+{
+ if(c == ';')
+ {
+ return true;
+ }
+ return false;
+}
+
+void ParsingToolBox::insertAlias(DiceAlias* dice, int i)
+{
+ if(i >= m_aliasList.size())
+ {
+ m_aliasList.insert(i, dice);
+ }
+}
+const QList<DiceAlias*>& ParsingToolBox::getAliases() const
+{
+ return m_aliasList;
+}
+
+QList<DiceAlias*>* ParsingToolBox::aliases()
+{
+ return &m_aliasList;
+}
+
+void ParsingToolBox::setAliases(const QList<DiceAlias*> list)
+{
+ qDeleteAll(m_aliasList);
+ m_aliasList.clear();
+ m_aliasList= list;
+}
+
+std::vector<ExecutionNode*> ParsingToolBox::readInstructionList(QString& str, bool global)
+{
+ if(str.isEmpty())
+ return {};
+
+ std::vector<ExecutionNode*> startNodes;
+
+ bool hasInstruction= false;
+ bool readInstruction= true;
+ while(readInstruction)
+ {
+ ExecutionNode* startNode= nullptr;
+ bool keepParsing= readExpression(str, startNode);
+ if(nullptr != startNode)
+ {
+ hasInstruction= true;
+ startNodes.push_back(startNode);
+ auto latest= startNode;
+ if(keepParsing)
+ {
+ latest= ParsingToolBox::getLeafNode(latest);
+ keepParsing= !str.isEmpty();
+ while(keepParsing)
+ {
+ auto before= str;
+ if(readOperator(str, latest))
+ {
+ latest= ParsingToolBox::getLeafNode(latest);
+ }
+ keepParsing= (!str.isEmpty() && (before != str));
+ }
+ }
+ if(!str.isEmpty() && readInstructionOperator(str[0]))
+ {
+ str= str.remove(0, 1);
+ }
+ else
+ {
+ QString result;
+ QString comment;
+ if(readComment(str, result, comment))
+ {
+ m_comment= result;
+ }
+ readInstruction= false;
+ }
+ }
+ else
+ {
+ readInstruction= false;
+ }
+ }
+ if(global)
+ m_startNodes= startNodes;
+ return startNodes;
+}
+
+SubtituteInfo ParsingToolBox::readVariableFromString(const QString& source, int& start)
+{
+ bool found= false;
+ SubtituteInfo info;
+ int i= start;
+ for(; i >= 0 && !found; --i)
+ {
+ if(source.at(i) == '$')
+ {
+ auto rest= source.mid(i + 1, 1 + start - i);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ auto len= QString::number(number).size() - 1;
+ readSubtitutionParameters(info, rest);
+ info.setLength(info.length() + len);
+ info.setResultIndex(static_cast<int>(number));
+ info.setPosition(i);
+ found= true;
+ }
+ }
+ }
+ start= i;
+ return info;
+}
+
+SubtituteInfo ParsingToolBox::readPlaceHolderFromString(const QString& source, int& start)
+{
+ bool found= false;
+ SubtituteInfo info;
+ int i= start;
+ for(; i >= 0 && !found; --i)
+ {
+ if(source.at(i) == '@')
+ {
+ auto rest= source.mid(i + 1, 1 + start - i);
+ qint64 number;
+ if(readNumber(rest, number))
+ {
+ auto len= QString::number(number).size() - 1;
+ readSubtitutionParameters(info, rest);
+ info.setLength(info.length() + len);
+ info.setResultIndex(static_cast<int>(number));
+ info.setPosition(i);
+ found= true;
+ }
+ }
+ }
+ start= i;
+ return info;
+}
+
+QString ParsingToolBox::number(qreal value)
+{
+ if(value > 1000000)
+ return QString::number(value, 'f', 20);
+ else
+ return QString::number(value);
+}
+
+ExportedDiceResult ParsingToolBox::finalDiceResultFromInstruction(ExecutionNode* start)
+{
+ ExecutionNode* next= ParsingToolBox::getLeafNode(start);
+ Result* result= next->getResult();
+ ExportedDiceResult nodeResult;
+ std::set<QString> alreadyAdded;
+ while(nullptr != result)
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ QList<HighLightDice> list;
+ quint64 faces= 0;
+ for(auto& die : diceResult->getResultList())
+ {
+ faces= die->getFaces();
+ HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(),
+ die->hasBeenDisplayed(), die->getFaces(), die->getUuid());
+ if(alreadyAdded.find(die->getUuid()) == alreadyAdded.end() && !hlDice.displayed())
+ {
+ list.append(hlDice);
+ alreadyAdded.insert(die->getUuid());
+ }
+ }
+ if(!list.isEmpty())
+ {
+ auto vals= nodeResult.value(faces);
+ vals.append(list);
+ nodeResult.insert(faces, vals);
+ }
+ }
+ /*if(nodeResult.isEmpty())
+ result= result->getPrevious();
+ else*/
+ result= result->getPrevious();
+ }
+ return nodeResult;
+}
+
+ExportedDiceResult ParsingToolBox::allDiceResultFromInstruction(ExecutionNode* start)
+{
+ ExecutionNode* next= ParsingToolBox::getLeafNode(start);
+ Result* result= next->getResult();
+ ExportedDiceResult nodeResult;
+ std::set<QString> alreadyAdded;
+ while(nullptr != result)
+ {
+ if(result->hasResultOfType(Dice::RESULT_TYPE::DICE_LIST))
+ {
+ DiceResult* diceResult= dynamic_cast<DiceResult*>(result);
+ QList<HighLightDice> list;
+ quint64 faces= 0;
+ for(auto& die : diceResult->getResultList())
+ {
+ faces= die->getFaces();
+ HighLightDice hlDice(die->getListValue(), die->isHighlighted(), die->getColor(),
+ die->hasBeenDisplayed(), die->getFaces(), die->getUuid());
+ if(alreadyAdded.find(die->getUuid()) == alreadyAdded.end())
+ {
+ list.append(hlDice);
+ alreadyAdded.insert(die->getUuid());
+ }
+ }
+ if(!list.isEmpty())
+ {
+ auto vals= nodeResult.value(faces);
+ vals.append(list);
+ nodeResult.insert(faces, vals);
+ }
+ }
+ result= result->getPrevious();
+ }
+ return nodeResult;
+}
+
+void ParsingToolBox::addResultInJson(QJsonObject& obj, Dice::RESULT_TYPE type, const QString& key, ExecutionNode* start,
+ bool b)
+{
+ auto pair= hasResultOfType(type, start, b);
+ if(pair.first)
+ obj[key]= QJsonValue::fromVariant(pair.second);
+}
+
+void ParsingToolBox::addDiceResultInJson(
+ QJsonObject& obj, ExecutionNode* start,
+ std::function<QString(const QString& value, const QString& color, bool highlighted)> colorize)
+{
+ QJsonArray diceValues;
+ auto result= ParsingToolBox::allDiceResultFromInstruction(start);
+ for(auto listOfList : result.values())
+ {
+ for(auto listDiceResult : listOfList)
+ {
+ for(auto hlDice : listDiceResult)
+ {
+ QJsonObject diceObj;
+ diceObj["face"]= static_cast<qreal>(hlDice.faces());
+ diceObj["color"]= hlDice.color();
+ diceObj["displayed"]= hlDice.displayed();
+ diceObj["string"]= colorize(hlDice.getResultString(), hlDice.color(), hlDice.isHighlighted());
+ diceObj["highlight"]= hlDice.isHighlighted();
+ diceObj["uuid"]= hlDice.uuid();
+ auto val= hlDice.result();
+ if(!val.isEmpty())
+ {
+ diceObj["value"]= std::accumulate(val.begin(), val.end(), 0);
+ if(val.size() > 1)
+ {
+ QJsonArray intValues;
+ std::transform(val.begin(), val.end(), std::back_inserter(intValues),
+ [](qint64 val) { return static_cast<int>(val); });
+ diceObj["subvalues"]= intValues;
+ }
+ }
+ diceValues.append(diceObj);
+ }
+ }
+ }
+ if(!diceValues.isEmpty())
+ obj["diceval"]= diceValues;
+}
+
+SubtituteInfo::SubtituteInfo() {}
+
+bool SubtituteInfo::isValid() const
+{
+ return !(m_position + m_resultIndex < 0);
+}
+
+int SubtituteInfo::length() const
+{
+ return m_length;
+}
+
+void SubtituteInfo::setLength(int length)
+{
+ m_length= length;
+}
+
+int SubtituteInfo::resultIndex() const
+{
+ return m_resultIndex;
+}
+
+void SubtituteInfo::setResultIndex(int valueIndex)
+{
+ m_resultIndex= valueIndex;
+}
+
+int SubtituteInfo::position() const
+{
+ return m_position;
+}
+
+void SubtituteInfo::setPosition(int position)
+{
+ m_position= position;
+}
+
+int SubtituteInfo::digitNumber() const
+{
+ return m_digitNumber;
+}
+
+void SubtituteInfo::setDigitNumber(int digitNumber)
+{
+ m_digitNumber= digitNumber;
+}
+
+int SubtituteInfo::subIndex() const
+{
+ return m_subIndex;
+}
+
+void SubtituteInfo::setSubIndex(int subindex)
+{
+ m_subIndex= subindex;
+}