diff --git a/Hazelnupp/Hazelnupp.cpp b/Hazelnupp/Hazelnupp.cpp index 948d3f6..7d5d646 100644 --- a/Hazelnupp/Hazelnupp.cpp +++ b/Hazelnupp/Hazelnupp.cpp @@ -463,6 +463,7 @@ std::string Hazelnupp::GenerateDocumentation() const << "==== AVAILABLE PARAMETERS ====" << std::endl << std::endl; + std::size_t counter = 0; for (const auto& it : paramInfos) { const ParamDocEntry& pde = it.second; @@ -490,8 +491,11 @@ std::string Hazelnupp::GenerateDocumentation() const if (pde.description.length() > 0) ss << pde.description; - if (&it.second != &(paramInfos.cend().operator--())->second) + // Omit linebreaks when we're on the last element + if (counter < paramInfos.size()-1) ss << std::endl << std::endl; + + counter++; } } diff --git a/INCLUDE/Hazelnupp.cpp b/INCLUDE/Hazelnupp.cpp index 3d9e6d6..d94a2a4 100644 --- a/INCLUDE/Hazelnupp.cpp +++ b/INCLUDE/Hazelnupp.cpp @@ -137,27 +137,27 @@ void Hazelnupp::Parse(const int argc, const char* const* argv) if ((!catchHelp) || (!HasParam("--help"))) ApplyConstraints(); } - catch (const HazelnuppConstraintTypeMissmatch& hctm) + catch (const HazelnuppConstraintTypeMissmatch& exc) { if (crashOnFail) { - std::cout << GenerateDocumentation() << std::endl; - std::cerr << "Fatal error: Command-line parameter value-type mismatch at \"" << hctm.What() << "\"!"; + std::cout << GenerateDocumentation() << std::endl << std::endl; + std::cerr << "Parameter error: " << exc.What() << std::endl; quick_exit(-1009); } else - throw hctm; // yeet + throw exc; // yeet } - catch (const HazelnuppConstraintMissingValue& hctm) + catch (const HazelnuppConstraintMissingValue& exc) { if (crashOnFail) { - std::cout << GenerateDocumentation() << std::endl; - std::cerr << "Fatal error: Missing required command-line parameter \"" << hctm.What() << "\"!"; + std::cout << GenerateDocumentation() << std::endl << std::endl; + std::cerr << "Parameter error: " << exc.What() << std::endl; quick_exit(-1010); } else - throw hctm; // yeet + throw exc; // yeet } // Catch --help parameter @@ -241,28 +241,44 @@ bool Hazelnupp::HasParam(const std::string& key) const Value* Hazelnupp::ParseValue(const std::vector& values, const ParamConstraint* constraint) { + // This is the raw (unconverted) data type the user provided + DATA_TYPE rawInputType; + // Constraint values const bool constrainType = (constraint != nullptr) && (constraint->constrainType); // Void-type if (values.size() == 0) { + rawInputType = DATA_TYPE::VOID; + // Is a list forced via a constraint? If yes, return an empty list if ((constrainType) && (constraint->wantedType == DATA_TYPE::LIST)) return new ListValue(); // Is a string forced via a constraint? If yes, return an empty string - if ((constrainType) && + else if ((constrainType) && (constraint->wantedType == DATA_TYPE::STRING)) return new StringValue(""); + // Is an int or float forced via constraint? If yes, throw an exception + else if ((constrainType) && + ((constraint->wantedType == DATA_TYPE::INT) || + (constraint->wantedType == DATA_TYPE::FLOAT))) + throw HazelnuppConstraintTypeMissmatch( + constraint->key, + constraint->wantedType, + rawInputType, + GetDescription(constraint->key) + ); + // Else, just return the void type return new VoidValue; } // Force void type by constraint - if ((constrainType) && + else if ((constrainType) && (constraint->wantedType == DATA_TYPE::VOID)) { return new VoidValue; @@ -271,11 +287,18 @@ Value* Hazelnupp::ParseValue(const std::vector& values, const Param // List-type else if (values.size() > 1) { + rawInputType = DATA_TYPE::LIST; + // Should the type be something other than list? if ((constrainType) && (constraint->wantedType != DATA_TYPE::LIST)) { - throw HazelnuppConstraintTypeMissmatch(values[0] + " " + values[1]); + throw HazelnuppConstraintTypeMissmatch( + constraint->key, + constraint->wantedType, + rawInputType, + GetDescription(constraint->key) + ); } ListValue* newList = new ListValue(); @@ -294,6 +317,8 @@ Value* Hazelnupp::ParseValue(const std::vector& values, const Param // String if (!StringTools::IsNumeric(val, true)) { + rawInputType = DATA_TYPE::STRING; + // Is the type not supposed to be a string? // void and list are already sorted out if ((constrainType) && @@ -309,9 +334,14 @@ Value* Hazelnupp::ParseValue(const std::vector& values, const Param tmp = nullptr; return list; } - // Else it not possible to convert to a numeric + // Else it is not possible to convert to a numeric else - throw HazelnuppConstraintTypeMissmatch(val); + throw HazelnuppConstraintTypeMissmatch( + constraint->key, + constraint->wantedType, + rawInputType, + GetDescription(constraint->key) + ); } return new StringValue(val); @@ -329,6 +359,8 @@ Value* Hazelnupp::ParseValue(const std::vector& values, const Param if (StringTools::ParseNumber(val, isInt, num)) { + rawInputType = isInt ? DATA_TYPE::INT : DATA_TYPE::FLOAT; + // Is the type constrained? // (only int and float left) if (constrainType) @@ -503,6 +535,7 @@ std::string Hazelnupp::GenerateDocumentation() const << "==== AVAILABLE PARAMETERS ====" << std::endl << std::endl; + std::size_t counter = 0; for (const auto& it : paramInfos) { const ParamDocEntry& pde = it.second; @@ -530,7 +563,11 @@ std::string Hazelnupp::GenerateDocumentation() const if (pde.description.length() > 0) ss << pde.description; - ss << std::endl << std::endl; + // Omit linebreaks when we're on the last element + if (counter < paramInfos.size()-1) + ss << std::endl << std::endl; + + counter++; } } @@ -564,7 +601,10 @@ void Hazelnupp::ApplyConstraints() // Is it important to have the missing parameter? if (pc.second.required) // Throw an error message then - throw HazelnuppConstraintMissingValue(pc.second.key); + throw HazelnuppConstraintMissingValue( + pc.second.key, + GetDescription(pc.second.key) + ); } } diff --git a/INCLUDE/Hazelnupp.h b/INCLUDE/Hazelnupp.h index 86e5dcd..18f7a85 100644 --- a/INCLUDE/Hazelnupp.h +++ b/INCLUDE/Hazelnupp.h @@ -1,5 +1,18 @@ #pragma once +/*** ../Hazelnupp/Placeholders.h ***/ + +#include + +namespace Hazelnp +{ + namespace Placeholders + { + //! The only purpose of this is to provide the ability to return an empty string as an error for std::string& methods. + static const std::string g_emptyString; + } +} + /*** ../Hazelnupp/StringTools.h ***/ #include @@ -42,89 +55,6 @@ namespace Hazelnp }; } -/*** ../Hazelnupp/Placeholders.h ***/ - -#include - -namespace Hazelnp -{ - namespace Placeholders - { - //! The only purpose of this is to provide the ability to return an empty string as an error for std::string& methods. - static const std::string g_emptyString; - } -} - -/*** ../Hazelnupp/HazelnuppException.h ***/ - -#include - -namespace Hazelnp -{ - /** Generic hazelnupp exception - */ - class HazelnuppException : public std::exception - { - public: - HazelnuppException() {}; - HazelnuppException(const std::string& msg) : message{ msg } {}; - - //! Will return an error message - const std::string& What() const - { - return message; - } - - protected: - std::string message; - }; - - /** Gets thrown when an non-existent key gets dereferenced - */ - class HazelnuppInvalidKeyException : public HazelnuppException - { - public: - HazelnuppInvalidKeyException() : HazelnuppException() {}; - HazelnuppInvalidKeyException(const std::string& msg) : HazelnuppException(msg) {}; - }; - - /** Gets thrown when an attempt is made to retrieve the wrong data type from a value, when the value not convertible - */ - class HazelnuppValueNotConvertibleException : public HazelnuppException - { - public: - HazelnuppValueNotConvertibleException() : HazelnuppException() {}; - HazelnuppValueNotConvertibleException(const std::string& msg) : HazelnuppException(msg) {}; - }; - - /** Gets thrown something bad happens because of parameter constraints - */ - class HazelnuppConstraintException : public HazelnuppException - { - public: - HazelnuppConstraintException() : HazelnuppException() {}; - HazelnuppConstraintException(const std::string& msg) : HazelnuppException(msg) {}; - }; - - /** Gets thrown when a parameter is of a type that does not match the required type, and is not convertible to it - */ - class HazelnuppConstraintTypeMissmatch : public HazelnuppConstraintException - { - public: - HazelnuppConstraintTypeMissmatch() : HazelnuppConstraintException() {}; - HazelnuppConstraintTypeMissmatch(const std::string& msg) : HazelnuppConstraintException(msg) {}; - }; - - /** Gets thrown when a parameter constrained to be required is not provided, and has no default value set - */ - class HazelnuppConstraintMissingValue : public HazelnuppConstraintException - { - public: - HazelnuppConstraintMissingValue() : HazelnuppConstraintException() {}; - HazelnuppConstraintMissingValue(const std::string& msg) : HazelnuppConstraintException(msg) {}; - }; -} - /*** ../Hazelnupp/DataType.h ***/ #include @@ -236,6 +166,105 @@ namespace Hazelnp }; } +/*** ../Hazelnupp/HazelnuppException.h ***/ + +#include +#include +#include + +namespace Hazelnp +{ + /** Generic hazelnupp exception + */ + class HazelnuppException : public std::exception + { + public: + HazelnuppException() {}; + HazelnuppException(const std::string& msg) : message{ msg } {}; + + //! Will return an error message + const std::string& What() const + { + return message; + } + + protected: + std::string message; + }; + + /** Gets thrown when an non-existent key gets dereferenced + */ + class HazelnuppInvalidKeyException : public HazelnuppException + { + public: + HazelnuppInvalidKeyException() : HazelnuppException() {}; + HazelnuppInvalidKeyException(const std::string& msg) : HazelnuppException(msg) {}; + }; + + /** Gets thrown when an attempt is made to retrieve the wrong data type from a value, when the value not convertible + */ + class HazelnuppValueNotConvertibleException : public HazelnuppException + { + public: + HazelnuppValueNotConvertibleException() : HazelnuppException() {}; + HazelnuppValueNotConvertibleException(const std::string& msg) : HazelnuppException(msg) {}; + }; + + /** Gets thrown something bad happens because of parameter constraints + */ + class HazelnuppConstraintException : public HazelnuppException + { + public: + HazelnuppConstraintException() : HazelnuppException() {}; + HazelnuppConstraintException(const std::string& msg) : HazelnuppException(msg) {}; + }; + + /** Gets thrown when a parameter is of a type that does not match the required type, and is not convertible to it + */ + class HazelnuppConstraintTypeMissmatch : public HazelnuppConstraintException + { + public: + HazelnuppConstraintTypeMissmatch() : HazelnuppConstraintException() {}; + HazelnuppConstraintTypeMissmatch(const std::string& msg) : HazelnuppConstraintException(msg) {}; + + HazelnuppConstraintTypeMissmatch(const std::string& key, const DATA_TYPE requiredType, const DATA_TYPE actualType, const std::string& paramDescription = "") + { + // Generate descriptive error message + std::stringstream ss; + ss << "Cannot convert parameter " << key << " to type " << DataTypeToString(requiredType) + << ". You supplied type: " << DataTypeToString(actualType) << "."; + + // Add the parameter description, if provided + if (paramDescription.length() > 0) + ss << std::endl << key << " => " << paramDescription; + + message = ss.str(); + return; + }; + }; + + /** Gets thrown when a parameter constrained to be required is not provided, and has no default value set + */ + class HazelnuppConstraintMissingValue : public HazelnuppConstraintException + { + public: + HazelnuppConstraintMissingValue() : HazelnuppConstraintException() {}; + HazelnuppConstraintMissingValue(const std::string& key, const std::string& paramDescription = "") + { + // Generate descriptive error message + std::stringstream ss; + ss << "Missing required parameter " << key << "."; + + // Add the parameter description, if provided + if (paramDescription.length() > 0) + ss << std::endl << key << " => " << paramDescription; + + message = ss.str(); + return; + }; + }; +} + /*** ../Hazelnupp/Value.h ***/ #include @@ -382,6 +411,53 @@ namespace Hazelnp }; } +/*** ../Hazelnupp/IntValue.h ***/ + + +namespace Hazelnp +{ + /** Specializations for integer values (uses long long int) + */ + class IntValue : public Value + { + public: + IntValue(const long long int& value); + ~IntValue() override {}; + + //! Will return a deeopopy of this object + Value* Deepcopy() const override; + + //! Will return a string suitable for an std::ostream; + std::string GetAsOsString() const override; + + //! Will return the raw value + const long long int& GetValue() const; + + operator long long int() const; + operator int() const; + + + //! Will return the data as a long long int + long long int GetInt64() const override; + //! Will return the data as an int + int GetInt32() const override; + + //! Will return the data as a long double + long double GetFloat64() const override; + //! Will return the data as a double + double GetFloat32() const override; + + //! Will return the data as a string + std::string GetString() const override; + + //! Throws HazelnuppValueNotConvertibleException + const std::vector& GetList() const override; + + private: + long long int value; + }; +} + /*** ../Hazelnupp/VoidValue.h ***/ @@ -449,53 +525,6 @@ namespace Hazelnp }; } -/*** ../Hazelnupp/IntValue.h ***/ - - -namespace Hazelnp -{ - /** Specializations for integer values (uses long long int) - */ - class IntValue : public Value - { - public: - IntValue(const long long int& value); - ~IntValue() override {}; - - //! Will return a deeopopy of this object - Value* Deepcopy() const override; - - //! Will return a string suitable for an std::ostream; - std::string GetAsOsString() const override; - - //! Will return the raw value - const long long int& GetValue() const; - - operator long long int() const; - operator int() const; - - - //! Will return the data as a long long int - long long int GetInt64() const override; - //! Will return the data as an int - int GetInt32() const override; - - //! Will return the data as a long double - long double GetFloat64() const override; - //! Will return the data as a double - double GetFloat32() const override; - - //! Will return the data as a string - std::string GetString() const override; - - //! Throws HazelnuppValueNotConvertibleException - const std::vector& GetList() const override; - - private: - long long int value; - }; -} - /*** ../Hazelnupp/Hazelnupp.h ***/ #include