diff options
author | Brad King <brad.king@kitware.com> | 2022-07-06 21:37:51 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-07-22 14:32:18 (GMT) |
commit | 50876f6b9afbf638fcc86ebfa83de7cc17a5a7e1 (patch) | |
tree | b38ecd3e45c229109b8f3f2e4f2d1d606c66cf40 | |
parent | 5955ec1992fbad26d89b9e3030276350708362c7 (diff) | |
download | CMake-50876f6b9afbf638fcc86ebfa83de7cc17a5a7e1.zip CMake-50876f6b9afbf638fcc86ebfa83de7cc17a5a7e1.tar.gz CMake-50876f6b9afbf638fcc86ebfa83de7cc17a5a7e1.tar.bz2 |
cmArgumentParser: Add structure to capture operational results
Create a way for the parser to record errors or incidental information
about the argument parsing operation that clients can inspect afterward.
Offer clients a way to hold the structure as part of their arguments
structure.
-rw-r--r-- | Source/cmArgumentParser.h | 50 | ||||
-rw-r--r-- | Tests/CMakeLib/testArgumentParser.cxx | 96 |
2 files changed, 98 insertions, 48 deletions
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 4079946..0078c04 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -12,6 +12,7 @@ #include <cm/optional> #include <cm/string_view> +#include <cm/type_traits> #include <cmext/string_view> #include "cmArgumentParserTypes.h" // IWYU pragma: keep @@ -21,6 +22,28 @@ class cmArgumentParser; // IWYU pragma: keep namespace ArgumentParser { +class ParseResult +{ +public: + explicit operator bool() const { return true; } +}; + +template <typename Result> +typename std::enable_if<std::is_base_of<ParseResult, Result>::value, + ParseResult*>::type +AsParseResultPtr(Result& result) +{ + return &result; +} + +template <typename Result> +typename std::enable_if<!std::is_base_of<ParseResult, Result>::value, + ParseResult*>::type +AsParseResultPtr(Result&) +{ + return nullptr; +} + class Instance; using KeywordAction = std::function<void(Instance&)>; @@ -44,6 +67,7 @@ class Base { public: using Instance = ArgumentParser::Instance; + using ParseResult = ArgumentParser::ParseResult; ArgumentParser::ActionMap Bindings; @@ -63,12 +87,13 @@ public: class Instance { public: - Instance(ActionMap const& bindings, + Instance(ActionMap const& bindings, ParseResult* parseResult, std::vector<std::string>* unparsedArguments, std::vector<cm::string_view>* keywordsMissingValue, std::vector<cm::string_view>* parsedKeywords, void* result = nullptr) : Bindings(bindings) + , ParseResults(parseResult) , UnparsedArguments(unparsedArguments) , KeywordsMissingValue(keywordsMissingValue) , ParsedKeywords(parsedKeywords) @@ -104,6 +129,7 @@ public: private: ActionMap const& Bindings; + ParseResult* ParseResults = nullptr; std::vector<std::string>* UnparsedArguments = nullptr; std::vector<cm::string_view>* KeywordsMissingValue = nullptr; std::vector<cm::string_view>* ParsedKeywords = nullptr; @@ -139,14 +165,17 @@ public: } template <typename Range> - void Parse(Result& result, Range const& args, + bool Parse(Result& result, Range const& args, std::vector<std::string>* unparsedArguments, std::vector<cm::string_view>* keywordsMissingValue = nullptr, std::vector<cm::string_view>* parsedKeywords = nullptr) const { - Instance instance(this->Bindings, unparsedArguments, keywordsMissingValue, - parsedKeywords, &result); + using ArgumentParser::AsParseResultPtr; + ParseResult* parseResultPtr = AsParseResultPtr(result); + Instance instance(this->Bindings, parseResultPtr, unparsedArguments, + keywordsMissingValue, parsedKeywords, &result); instance.Parse(args); + return parseResultPtr ? static_cast<bool>(*parseResultPtr) : true; } template <typename Range> @@ -173,13 +202,16 @@ public: } template <typename Range> - void Parse(Range const& args, std::vector<std::string>* unparsedArguments, - std::vector<cm::string_view>* keywordsMissingValue = nullptr, - std::vector<cm::string_view>* parsedKeywords = nullptr) const + ParseResult Parse( + Range const& args, std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { - Instance instance(this->Bindings, unparsedArguments, keywordsMissingValue, - parsedKeywords); + ParseResult parseResult; + Instance instance(this->Bindings, &parseResult, unparsedArguments, + keywordsMissingValue, parsedKeywords); instance.Parse(args); + return parseResult; } protected: diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index ecfc5fc..054cfd5 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -15,7 +15,7 @@ namespace { -struct Result +struct Result : public ArgumentParser::ParseResult { bool Option1 = false; bool Option2 = false; @@ -78,6 +78,8 @@ bool verifyResult(Result const& result, } \ } while (false) + ASSERT_TRUE(result); + ASSERT_TRUE(result.Option1); ASSERT_TRUE(!result.Option2); @@ -119,54 +121,65 @@ bool testArgumentParserDynamic() std::vector<std::string> unparsedArguments; std::vector<cm::string_view> keywordsMissingValue; - cmArgumentParser<void>{} - .Bind("OPTION_1"_s, result.Option1) - .Bind("OPTION_2"_s, result.Option2) - .Bind("STRING_1"_s, result.String1) - .Bind("STRING_2"_s, result.String2) - .Bind("STRING_3"_s, result.String3) - .Bind("STRING_4"_s, result.String4) - .Bind("LIST_1"_s, result.List1) - .Bind("LIST_2"_s, result.List2) - .Bind("LIST_3"_s, result.List3) - .Bind("LIST_4"_s, result.List4) - .Bind("LIST_5"_s, result.List5) - .Bind("LIST_6"_s, result.List6) - .Bind("MULTI_1"_s, result.Multi1) - .Bind("MULTI_2"_s, result.Multi2) - .Bind("MULTI_3"_s, result.Multi3) - .Bind("MULTI_4"_s, result.Multi4) - .Parse(args, &unparsedArguments, &keywordsMissingValue); + static_cast<ArgumentParser::ParseResult&>(result) = + cmArgumentParser<void>{} + .Bind("OPTION_1"_s, result.Option1) + .Bind("OPTION_2"_s, result.Option2) + .Bind("STRING_1"_s, result.String1) + .Bind("STRING_2"_s, result.String2) + .Bind("STRING_3"_s, result.String3) + .Bind("STRING_4"_s, result.String4) + .Bind("LIST_1"_s, result.List1) + .Bind("LIST_2"_s, result.List2) + .Bind("LIST_3"_s, result.List3) + .Bind("LIST_4"_s, result.List4) + .Bind("LIST_5"_s, result.List5) + .Bind("LIST_6"_s, result.List6) + .Bind("MULTI_1"_s, result.Multi1) + .Bind("MULTI_2"_s, result.Multi2) + .Bind("MULTI_3"_s, result.Multi3) + .Bind("MULTI_4"_s, result.Multi4) + .Parse(args, &unparsedArguments, &keywordsMissingValue); return verifyResult(result, unparsedArguments, keywordsMissingValue); } +static auto const parserStatic = // + cmArgumentParser<Result>{} + .Bind("OPTION_1"_s, &Result::Option1) + .Bind("OPTION_2"_s, &Result::Option2) + .Bind("STRING_1"_s, &Result::String1) + .Bind("STRING_2"_s, &Result::String2) + .Bind("STRING_3"_s, &Result::String3) + .Bind("STRING_4"_s, &Result::String4) + .Bind("LIST_1"_s, &Result::List1) + .Bind("LIST_2"_s, &Result::List2) + .Bind("LIST_3"_s, &Result::List3) + .Bind("LIST_4"_s, &Result::List4) + .Bind("LIST_5"_s, &Result::List5) + .Bind("LIST_6"_s, &Result::List6) + .Bind("MULTI_1"_s, &Result::Multi1) + .Bind("MULTI_2"_s, &Result::Multi2) + .Bind("MULTI_3"_s, &Result::Multi3) + .Bind("MULTI_4"_s, &Result::Multi4) + /* keep semicolon on own line */; + bool testArgumentParserStatic() { - static auto const parser = // - cmArgumentParser<Result>{} - .Bind("OPTION_1"_s, &Result::Option1) - .Bind("OPTION_2"_s, &Result::Option2) - .Bind("STRING_1"_s, &Result::String1) - .Bind("STRING_2"_s, &Result::String2) - .Bind("STRING_3"_s, &Result::String3) - .Bind("STRING_4"_s, &Result::String4) - .Bind("LIST_1"_s, &Result::List1) - .Bind("LIST_2"_s, &Result::List2) - .Bind("LIST_3"_s, &Result::List3) - .Bind("LIST_4"_s, &Result::List4) - .Bind("LIST_5"_s, &Result::List5) - .Bind("LIST_6"_s, &Result::List6) - .Bind("MULTI_1"_s, &Result::Multi1) - .Bind("MULTI_2"_s, &Result::Multi2) - .Bind("MULTI_3"_s, &Result::Multi3) - .Bind("MULTI_4"_s, &Result::Multi4); - std::vector<std::string> unparsedArguments; std::vector<cm::string_view> keywordsMissingValue; Result const result = - parser.Parse(args, &unparsedArguments, &keywordsMissingValue); + parserStatic.Parse(args, &unparsedArguments, &keywordsMissingValue); + return verifyResult(result, unparsedArguments, keywordsMissingValue); +} +bool testArgumentParserStaticBool() +{ + std::vector<std::string> unparsedArguments; + std::vector<cm::string_view> keywordsMissingValue; + Result result; + ASSERT_TRUE(parserStatic.Parse(result, args, &unparsedArguments, + &keywordsMissingValue) == true); return verifyResult(result, unparsedArguments, keywordsMissingValue); } @@ -184,5 +197,10 @@ int testArgumentParser(int /*unused*/, char* /*unused*/ []) return -1; } + if (!testArgumentParserStaticBool()) { + std::cout << "While executing testArgumentParserStaticBool().\n"; + return -1; + } + return 0; } |