File indexing completed on 2024-04-28 05:36:59

0001 /***************************************************************************
0002  * Copyright (C) 2014 by Renaud Guezennec                                   *
0003  * https://rolisteam.org/contact                      *
0004  *                                                                          *
0005  *  This file is part of DiceParser                                         *
0006  *                                                                          *
0007  * DiceParser is free software; you can redistribute it and/or modify       *
0008  * it under the terms of the GNU General Public License as published by     *
0009  * the Free Software Foundation; either version 2 of the License, or        *
0010  * (at your option) any later version.                                      *
0011  *                                                                          *
0012  * This program is distributed in the hope that it will be useful,          *
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of           *
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the             *
0015  * GNU General Public License for more details.                             *
0016  *                                                                          *
0017  * You should have received a copy of the GNU General Public License        *
0018  * along with this program; if not, write to the                            *
0019  * Free Software Foundation, Inc.,                                          *
0020  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.                 *
0021  ***************************************************************************/
0022 #include <diceparser/diceparser.h>
0023 
0024 #include <QDebug>
0025 #include <QFile>
0026 #include <QJsonArray>
0027 #include <QJsonDocument>
0028 #include <QJsonObject>
0029 #include <QObject>
0030 #include <QStringList>
0031 #include <functional>
0032 #include <numeric>
0033 
0034 #include "booleancondition.h"
0035 #include "range.h"
0036 #include "result/stringresult.h"
0037 #include "validator.h"
0038 #include <diceparser/dicealias.h>
0039 #include <diceparser/parsingtoolbox.h>
0040 
0041 #define DEFAULT_FACES_NUMBER 10
0042 
0043 DiceParser::DiceParser() : m_parsingToolbox(new ParsingToolBox()) {}
0044 DiceParser::~DiceParser() {}
0045 
0046 const QList<DiceAlias*>& DiceParser::constAliases() const
0047 {
0048     return m_parsingToolbox->getAliases();
0049 }
0050 
0051 QList<DiceAlias*>* DiceParser::aliases() const
0052 {
0053     return m_parsingToolbox->aliases();
0054 }
0055 
0056 void DiceParser::cleanAliases()
0057 {
0058     m_parsingToolbox->cleanUpAliases();
0059 }
0060 void DiceParser::insertAlias(DiceAlias* dice, int i)
0061 {
0062     m_parsingToolbox->insertAlias(dice, i);
0063 }
0064 
0065 bool DiceParser::parseLine(QString str, bool allowAlias)
0066 {
0067     if(allowAlias)
0068     {
0069         str= m_parsingToolbox->convertAlias(str);
0070     }
0071     m_parsingToolbox->clearUp();
0072     m_command= str;
0073     auto instructions= m_parsingToolbox->readInstructionList(str, true);
0074     m_command.remove(m_parsingToolbox->getComment());
0075     bool value= !instructions.empty();
0076     if(!value)
0077     {
0078         m_parsingToolbox->addError(Dice::ERROR_CODE::NOTHING_UNDERSTOOD,
0079                                    QObject::tr("Nothing was understood. To roll dice: !1d6 - full documentation: "
0080                                                "<a "
0081                                                "href=\"https://github.com/Rolisteam/DiceParser/blob/master/"
0082                                                "HelpMe.md\">https://github.com/"
0083                                                "Rolisteam/DiceParser/blob/master/HelpMe.md</a>"));
0084     }
0085     else if(value && !str.isEmpty())
0086     {
0087         auto i= m_command.size() - str.size();
0088         m_parsingToolbox->addWarning(
0089             Dice::ERROR_CODE::UNEXPECTED_CHARACTER,
0090             QObject::tr("Unexpected character at %1 - end of command was ignored \"%2\"").arg(i).arg(str));
0091     }
0092 
0093     if(m_parsingToolbox->hasError())
0094         value= false;
0095 
0096     return value;
0097 }
0098 
0099 QString DiceParser::convertAlias(const QString& cmd) const
0100 {
0101     return m_parsingToolbox->convertAlias(cmd);
0102 }
0103 
0104 void DiceParser::start()
0105 {
0106     for(auto start : m_parsingToolbox->getStartNodes())
0107     {
0108         start->run();
0109     }
0110 }
0111 
0112 QString DiceParser::diceCommand() const
0113 {
0114     return m_command;
0115 }
0116 
0117 bool DiceParser::hasIntegerResultNotInFirst() const
0118 {
0119     return m_parsingToolbox->hasIntegerResultNotInFirst();
0120 }
0121 
0122 bool DiceParser::hasDiceResult() const
0123 {
0124     return m_parsingToolbox->hasDiceResult();
0125 }
0126 bool DiceParser::hasStringResult() const
0127 {
0128     return m_parsingToolbox->hasStringResult();
0129 }
0130 
0131 int DiceParser::startNodeCount() const
0132 {
0133     return static_cast<int>(m_parsingToolbox->getStartNodes().size());
0134 }
0135 
0136 QList<qreal> DiceParser::scalarResultsFromEachInstruction() const
0137 {
0138     return m_parsingToolbox->scalarResultsFromEachInstruction();
0139 }
0140 
0141 QStringList DiceParser::stringResultFromEachInstruction(bool& hasAlias) const
0142 {
0143     return m_parsingToolbox->allFirstResultAsString(hasAlias);
0144 }
0145 
0146 void DiceParser::diceResultFromEachInstruction(QList<ExportedDiceResult>& resultList) const
0147 {
0148     resultList= m_parsingToolbox->diceResultFromEachInstruction();
0149 }
0150 
0151 QString DiceParser::comment() const
0152 {
0153     return m_parsingToolbox->getComment();
0154 }
0155 
0156 void DiceParser::setComment(const QString& comment)
0157 {
0158     m_parsingToolbox->setComment(comment);
0159 }
0160 
0161 QMap<Dice::ERROR_CODE, QString> DiceParser::errorMap() const
0162 {
0163     QMap<Dice::ERROR_CODE, QString> map;
0164 
0165     for(auto start : m_parsingToolbox->getStartNodes())
0166     {
0167         auto mapTmp= start->getExecutionErrorMap();
0168         auto keys= mapTmp.keys();
0169         for(auto& key : keys)
0170         {
0171             map.insert(key, mapTmp[key]);
0172         }
0173     }
0174     return map;
0175 }
0176 QString DiceParser::humanReadableError() const
0177 {
0178     auto parsingError= m_parsingToolbox->getErrorList();
0179     QString str;
0180     std::for_each(parsingError.begin(), parsingError.end(),
0181                   [&str](const QString& text)
0182                   {
0183                       str.append(text);
0184                       str.append(QStringLiteral("\n"));
0185                   });
0186 
0187     /// list
0188     auto errMap= errorMap();
0189     std::for_each(errMap.begin(), errMap.end(),
0190                   [&str](const QString& text)
0191                   {
0192                       str.append(text);
0193                       str.append(QStringLiteral("\n"));
0194                   });
0195     return str;
0196 }
0197 
0198 QString DiceParser::humanReadableWarning() const
0199 {
0200     auto warningMap= m_parsingToolbox->getWarningList();
0201     QMapIterator<Dice::ERROR_CODE, QString> i(warningMap);
0202     QString str("");
0203     while(i.hasNext())
0204     {
0205         i.next();
0206         str.append(i.value());
0207         str.append(QStringLiteral("\n"));
0208     }
0209     return str;
0210 }
0211 
0212 QString DiceParser::finalStringResult(std::function<QString(const QString&, const QString&, bool)> colorize) const
0213 {
0214     return m_parsingToolbox->finalStringResult(colorize);
0215 }
0216 
0217 QString DiceParser::resultAsJSon(std::function<QString(const QString&, const QString&, bool)> colorize,
0218                                  bool removeUnhighligthed) const
0219 {
0220     QJsonObject obj;
0221     QJsonArray instructions;
0222     for(auto start : m_parsingToolbox->getStartNodes())
0223     {
0224         QJsonObject inst;
0225 
0226         m_parsingToolbox->addResultInJson(inst, Dice::RESULT_TYPE::SCALAR, "scalar", start, true);
0227         m_parsingToolbox->addResultInJson(inst, Dice::RESULT_TYPE::STRING, "string", start, false);
0228         m_parsingToolbox->addDiceResultInJson(inst, start, colorize);
0229 
0230         instructions.append(inst);
0231     }
0232     obj["instructions"]= instructions;
0233     obj["comment"]= m_parsingToolbox->getComment();
0234     obj["error"]= humanReadableError();
0235     obj["scalar"]= m_parsingToolbox->finalScalarResult().first;
0236     obj["string"]= m_parsingToolbox->finalStringResult(colorize, removeUnhighligthed);
0237     obj["warning"]= humanReadableWarning();
0238     obj["command"]= m_command;
0239 
0240     QJsonDocument doc;
0241     doc.setObject(obj);
0242     return doc.toJson();
0243 }
0244 
0245 void DiceParser::writeDownDotTree(QString filepath)
0246 {
0247     if(m_parsingToolbox->getStartNodes().empty())
0248         return;
0249 
0250     QString str(QStringLiteral("digraph ExecutionTree {\n"));
0251     for(auto start : m_parsingToolbox->getStartNodes())
0252     {
0253         start->generateDotTree(str);
0254     }
0255     str.append(QStringLiteral("}\n"));
0256 
0257     QFile file(filepath);
0258     if(file.open(QIODevice::WriteOnly))
0259     {
0260         QTextStream in(&file);
0261         in << str;
0262     }
0263 }
0264 void DiceParser::setPathToHelp(QString l)
0265 {
0266     m_parsingToolbox->setHelpPath(l);
0267 }
0268 void DiceParser::setVariableDictionary(const QHash<QString, QString>& variables)
0269 {
0270     ParsingToolBox::setVariableHash(variables);
0271 }