From 9fd183e0cdb9d21627d1581882970e984bc0ba70 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 2 Jun 2021 19:20:50 +0200 Subject: [PATCH] Implemented constraint for forced types --- Hazelnupp/Hazelnupp.cpp | 109 ++++++++++++++++++++++++++-- Hazelnupp/Hazelnupp.h | 14 +++- Hazelnupp/Hazelnupp.vcxproj | 2 + Hazelnupp/Hazelnupp.vcxproj.filters | 6 ++ Hazelnupp/HazelnuppException.h | 5 ++ Hazelnupp/ParamConstraint.h | 25 +++++++ Hazelnupp/main.cpp | 14 +++- 7 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 Hazelnupp/HazelnuppException.h create mode 100644 Hazelnupp/ParamConstraint.h diff --git a/Hazelnupp/Hazelnupp.cpp b/Hazelnupp/Hazelnupp.cpp index cbd41f3..1a576e3 100644 --- a/Hazelnupp/Hazelnupp.cpp +++ b/Hazelnupp/Hazelnupp.cpp @@ -4,6 +4,7 @@ #include "FloatValue.h" #include "StringValue.h" #include "ListValue.h" +#include "HazelnuppException.h" #include "StringTools.h" Hazelnupp::Hazelnupp() @@ -70,7 +71,10 @@ std::size_t Hazelnupp::ParseNextParameter(const std::size_t parIndex, Parameter* break; } - Value* parsedVal = ParseValue(values); + // Fetch constraint info + const ParamConstraint* pcn = GetConstraintForKey(key); + + Value* parsedVal = ParseValue(values, pcn); if (parsedVal != nullptr) { out_Par = new Parameter(key, parsedVal); @@ -116,21 +120,38 @@ bool Hazelnupp::HasParam(const std::string& key) const return parameters.find(key) != parameters.end(); } -Value* Hazelnupp::ParseValue(const std::vector& values) +Value* Hazelnupp::ParseValue(const std::vector& values, const ParamConstraint* constraint) { + // Constraint values + const bool constrainType = (constraint != nullptr) && (constraint->constrainType); + // Void-type if (values.size() == 0) { return new VoidValue; } + // Force void type by constraint + if ((constrainType) && + (constraint->wantedType == DATA_TYPE::VOID)) + { + return new VoidValue; + } + // List-type 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(); for (const std::string& val : values) { - Value* tmp = ParseValue(std::vector({ val })); + Value* tmp = ParseValue({ val }); newList->AddValue(tmp); delete tmp; } @@ -142,6 +163,34 @@ Value* Hazelnupp::ParseValue(const std::vector& values) // String 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); // Numeric @@ -150,12 +199,37 @@ Value* Hazelnupp::ParseValue(const std::vector& values) if (StringTools::ParseNumber(val, isInt, num)) { - // Integer - if (isInt) - return new IntValue((long long int)num); + // Is the type constrained? + // (only int and float left) + 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 - return new FloatValue(num); + // Double + return new FloatValue(num); + } } // Failed @@ -187,3 +261,22 @@ bool Hazelnupp::HasAbbreviation(const std::string& abbrev) const { return abbreviations.find(abbrev) != abbreviations.end(); } + +void Hazelnupp::AddConstraints(const std::vector& constraints) +{ + for (const ParamConstraint& pc : constraints) + this->constraints.insert(std::pair( + 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; +} diff --git a/Hazelnupp/Hazelnupp.h b/Hazelnupp/Hazelnupp.h index cf1fcdf..b50ed88 100644 --- a/Hazelnupp/Hazelnupp.h +++ b/Hazelnupp/Hazelnupp.h @@ -1,5 +1,6 @@ #pragma once #include "Parameter.h" +#include "ParamConstraint.h" #include #include @@ -33,6 +34,8 @@ public: //! Will check wether or not an abbreviation is registered bool HasAbbreviation(const std::string& abbrev) const; + void AddConstraints(const std::vector& constraints); + private: //! Will translate the c-like args to an std::vector 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); //! Will convert a vector of string-values to an actual Value - Value* ParseValue(const std::vector& values); + Value* ParseValue(const std::vector& 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::unordered_map parameters; @@ -52,5 +61,8 @@ private: // These are abbreviations. Like, -f for --force. std::unordered_map abbreviations; + // Parameter constraints, mapped to keys + std::unordered_map constraints; + std::vector rawArgs; }; diff --git a/Hazelnupp/Hazelnupp.vcxproj b/Hazelnupp/Hazelnupp.vcxproj index 71eb82d..88ae8dc 100644 --- a/Hazelnupp/Hazelnupp.vcxproj +++ b/Hazelnupp/Hazelnupp.vcxproj @@ -153,8 +153,10 @@ + + diff --git a/Hazelnupp/Hazelnupp.vcxproj.filters b/Hazelnupp/Hazelnupp.vcxproj.filters index 9f6c39e..fb7afa6 100644 --- a/Hazelnupp/Hazelnupp.vcxproj.filters +++ b/Hazelnupp/Hazelnupp.vcxproj.filters @@ -77,5 +77,11 @@ Headerdateien + + Headerdateien + + + Headerdateien + \ No newline at end of file diff --git a/Hazelnupp/HazelnuppException.h b/Hazelnupp/HazelnuppException.h new file mode 100644 index 0000000..ba043d4 --- /dev/null +++ b/Hazelnupp/HazelnuppException.h @@ -0,0 +1,5 @@ +#pragma once +#include + +class HazelnutException : public std::exception {}; +class HazelnutConstraintMissmatch : public HazelnutException {}; diff --git a/Hazelnupp/ParamConstraint.h b/Hazelnupp/ParamConstraint.h new file mode 100644 index 0000000..b6b0815 --- /dev/null +++ b/Hazelnupp/ParamConstraint.h @@ -0,0 +1,25 @@ +#pragma once +#include "DataType.h" +#include + +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; +}; diff --git a/Hazelnupp/main.cpp b/Hazelnupp/main.cpp index c0bb028..c338a2a 100644 --- a/Hazelnupp/main.cpp +++ b/Hazelnupp/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) std::vector testArgv = { "meinpfad", "-w", - "123", + "-99", "--alfred", "apfel", "banane", @@ -24,6 +24,16 @@ int main(int argc, char** argv) 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.Parse(testArgv.size(), testArgv.data()); @@ -31,7 +41,7 @@ int main(int argc, char** argv) if (args.HasParam("--word")) { - std::cout << args["--word"]->GetString() << std::endl; + std::cout << *args["--word"] << std::endl; } else {