Implemented constraint for forced types

This commit is contained in:
Leonetienne 2021-06-02 19:20:50 +02:00
parent a2de37264a
commit 9fd183e0cd
7 changed files with 164 additions and 11 deletions

View File

@ -4,6 +4,7 @@
#include "FloatValue.h" #include "FloatValue.h"
#include "StringValue.h" #include "StringValue.h"
#include "ListValue.h" #include "ListValue.h"
#include "HazelnuppException.h"
#include "StringTools.h" #include "StringTools.h"
Hazelnupp::Hazelnupp() Hazelnupp::Hazelnupp()
@ -70,7 +71,10 @@ std::size_t Hazelnupp::ParseNextParameter(const std::size_t parIndex, Parameter*
break; break;
} }
Value* parsedVal = ParseValue(values); // Fetch constraint info
const ParamConstraint* pcn = GetConstraintForKey(key);
Value* parsedVal = ParseValue(values, pcn);
if (parsedVal != nullptr) if (parsedVal != nullptr)
{ {
out_Par = new Parameter(key, parsedVal); out_Par = new Parameter(key, parsedVal);
@ -116,21 +120,38 @@ bool Hazelnupp::HasParam(const std::string& key) const
return parameters.find(key) != parameters.end(); return parameters.find(key) != parameters.end();
} }
Value* Hazelnupp::ParseValue(const std::vector<std::string>& values) Value* Hazelnupp::ParseValue(const std::vector<std::string>& values, const ParamConstraint* constraint)
{ {
// Constraint values
const bool constrainType = (constraint != nullptr) && (constraint->constrainType);
// Void-type // Void-type
if (values.size() == 0) if (values.size() == 0)
{ {
return new VoidValue; return new VoidValue;
} }
// Force void type by constraint
if ((constrainType) &&
(constraint->wantedType == DATA_TYPE::VOID))
{
return new VoidValue;
}
// List-type // List-type
else if (values.size() > 1) else if (values.size() > 1)
{ {
// Should the type be something other than list?
if ((constrainType) &&
(constraint->wantedType != DATA_TYPE::LIST))
{
throw HazelnutConstraintMissmatch();
}
ListValue* newList = new ListValue(); ListValue* newList = new ListValue();
for (const std::string& val : values) for (const std::string& val : values)
{ {
Value* tmp = ParseValue(std::vector<std::string>({ val })); Value* tmp = ParseValue({ val });
newList->AddValue(tmp); newList->AddValue(tmp);
delete tmp; delete tmp;
} }
@ -142,6 +163,34 @@ Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
// String // String
if (!StringTools::IsNumeric(val, true)) if (!StringTools::IsNumeric(val, true))
{
// Is the type not supposed to be a string?
// void and list are already sorted out
if ((constrainType) &&
(constraint->wantedType != DATA_TYPE::STRING))
{
// We can only force a list-value from here
if (constraint->wantedType == DATA_TYPE::LIST)
{
ListValue* list = new ListValue();
Value* tmp = ParseValue({ val });
list->AddValue(tmp);
delete tmp;
tmp = nullptr;
return list;
}
// Else it not possible to convert to a numeric
else
throw HazelnutConstraintMissmatch();
}
return new StringValue(val);
}
// In this case we have a numeric value.
// We should still produce a string if requested
if ((constrainType) &&
(constraint->wantedType == DATA_TYPE::STRING))
return new StringValue(val); return new StringValue(val);
// Numeric // Numeric
@ -150,12 +199,37 @@ Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
if (StringTools::ParseNumber(val, isInt, num)) if (StringTools::ParseNumber(val, isInt, num))
{ {
// Integer // Is the type constrained?
if (isInt) // (only int and float left)
return new IntValue((long long int)num); if (constrainType)
{
// Must it be an integer?
if (constraint->wantedType == DATA_TYPE::INT)
return new IntValue((long long int)num);
// Must it be a floating point?
else if (constraint->wantedType == DATA_TYPE::FLOAT)
return new FloatValue(num);
// Else it must be a List
else
{
ListValue* list = new ListValue();
Value* tmp = ParseValue({ val });
list->AddValue(tmp);
delete tmp;
tmp = nullptr;
return list;
}
}
// Type is not constrained
else
{
// Integer
if (isInt)
return new IntValue((long long int)num);
// Double // Double
return new FloatValue(num); return new FloatValue(num);
}
} }
// Failed // Failed
@ -187,3 +261,22 @@ bool Hazelnupp::HasAbbreviation(const std::string& abbrev) const
{ {
return abbreviations.find(abbrev) != abbreviations.end(); return abbreviations.find(abbrev) != abbreviations.end();
} }
void Hazelnupp::AddConstraints(const std::vector<ParamConstraint>& constraints)
{
for (const ParamConstraint& pc : constraints)
this->constraints.insert(std::pair<std::string, ParamConstraint>(
pc.key,
pc
));
}
const ParamConstraint* Hazelnupp::GetConstraintForKey(const std::string& key) const
{
const auto constraint = constraints.find(key);
if (constraint == constraints.end())
return nullptr;
return &constraint->second;
}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Parameter.h" #include "Parameter.h"
#include "ParamConstraint.h"
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -33,6 +34,8 @@ public:
//! Will check wether or not an abbreviation is registered //! Will check wether or not an abbreviation is registered
bool HasAbbreviation(const std::string& abbrev) const; bool HasAbbreviation(const std::string& abbrev) const;
void AddConstraints(const std::vector<ParamConstraint>& constraints);
private: private:
//! Will translate the c-like args to an std::vector //! Will translate the c-like args to an std::vector
void PopulateRawArgs(const int argc, const char* const* argv); void PopulateRawArgs(const int argc, const char* const* argv);
@ -44,7 +47,13 @@ private:
std::size_t ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par); std::size_t ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par);
//! Will convert a vector of string-values to an actual Value //! Will convert a vector of string-values to an actual Value
Value* ParseValue(const std::vector<std::string>& values); Value* ParseValue(const std::vector<std::string>& values, const ParamConstraint* constraint = nullptr);
//! Will apply the loaded constraints on the loaded values.
void ApplyConstraints();
//! Will return a pointer to a paramConstraint given a key. If there is no, it returns nullptr
const ParamConstraint* GetConstraintForKey(const std::string& key) const;
std::string executableName; //! The path of the executable. Always argv[0] std::string executableName; //! The path of the executable. Always argv[0]
std::unordered_map<std::string, Parameter*> parameters; std::unordered_map<std::string, Parameter*> parameters;
@ -52,5 +61,8 @@ private:
// These are abbreviations. Like, -f for --force. // These are abbreviations. Like, -f for --force.
std::unordered_map<std::string, std::string> abbreviations; std::unordered_map<std::string, std::string> abbreviations;
// Parameter constraints, mapped to keys
std::unordered_map<std::string, ParamConstraint> constraints;
std::vector<std::string> rawArgs; std::vector<std::string> rawArgs;
}; };

View File

@ -153,8 +153,10 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="FloatValue.h" /> <ClInclude Include="FloatValue.h" />
<ClInclude Include="Hazelnupp.h" /> <ClInclude Include="Hazelnupp.h" />
<ClInclude Include="HazelnuppException.h" />
<ClInclude Include="IntValue.h" /> <ClInclude Include="IntValue.h" />
<ClInclude Include="ListValue.h" /> <ClInclude Include="ListValue.h" />
<ClInclude Include="ParamConstraint.h" />
<ClInclude Include="Parameter.h" /> <ClInclude Include="Parameter.h" />
<ClInclude Include="DataType.h" /> <ClInclude Include="DataType.h" />
<ClInclude Include="StringTools.h" /> <ClInclude Include="StringTools.h" />

View File

@ -77,5 +77,11 @@
<ClInclude Include="StringTools.h"> <ClInclude Include="StringTools.h">
<Filter>Headerdateien</Filter> <Filter>Headerdateien</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ParamConstraint.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="HazelnuppException.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdexcept>
class HazelnutException : public std::exception {};
class HazelnutConstraintMissmatch : public HazelnutException {};

View File

@ -0,0 +1,25 @@
#pragma once
#include "DataType.h"
#include <string>
struct ParamConstraint
{
public:
//! The key of the parameter to constrain
std::string key;
//! Should this parameter be forced to be of a certain type?
//! Remember to set `constrainTo` to the wanted type
bool constrainType = false;
//! Constrain the parameter to this value. Requires `constrainType` to be set to true.
DATA_TYPE wantedType;
//! The default value for this parameter.
//! Gets applied if this parameter was not given.
std::string defaultValue;
//! If set to true, and no default value set,
//! an error will be produced if this parameter is not supplied by the user.
bool required = false;
};

View File

@ -9,7 +9,7 @@ int main(int argc, char** argv)
std::vector<const char*> testArgv = { std::vector<const char*> testArgv = {
"meinpfad", "meinpfad",
"-w", "-w",
"123", "-99",
"--alfred", "--alfred",
"apfel", "apfel",
"banane", "banane",
@ -24,6 +24,16 @@ int main(int argc, char** argv)
Hazelnupp args; Hazelnupp args;
ParamConstraint pc;
pc.key = "--word";
pc.constrainType = true;
pc.wantedType = DATA_TYPE::INT;
pc.required = true;
args.AddConstraints({
pc
});
args.RegisterAbbreviation("-w", "--word"); args.RegisterAbbreviation("-w", "--word");
args.Parse(testArgv.size(), testArgv.data()); args.Parse(testArgv.size(), testArgv.data());
@ -31,7 +41,7 @@ int main(int argc, char** argv)
if (args.HasParam("--word")) if (args.HasParam("--word"))
{ {
std::cout << args["--word"]->GetString() << std::endl; std::cout << *args["--word"] << std::endl;
} }
else else
{ {