diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 104436be87..ea9261134e 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -56,8 +56,8 @@ auto PositionActionMap::Find(std::size_t pos) const -> const_iterator void Instance::Bind(std::function f, ExpectAtLeast expect) { - this->KeywordValueFunc = std::move(f); - this->KeywordValuesExpected = expect.Count; + this->GetState().KeywordValueFunc = std::move(f); + this->GetState().KeywordValuesExpected = expect.Count; } void Instance::Bind(bool& val) @@ -81,7 +81,7 @@ void Instance::Bind(NonEmpty& val) this->Bind( [this, &val](cm::string_view arg) -> Continue { if (arg.empty() && this->ParseResults) { - this->ParseResults->AddKeywordError(this->Keyword, + this->ParseResults->AddKeywordError(this->GetState().Keyword, " empty string not allowed\n"); } val = std::string(arg); @@ -132,48 +132,50 @@ void Instance::Bind(std::vector>& multiVal) ExpectAtLeast{ 0 }); } -void Instance::Consume(std::size_t pos, cm::string_view arg) +void Instance::Consume(cm::string_view arg) { - auto const it = this->Bindings.Keywords.Find(arg); - if (it != this->Bindings.Keywords.end()) { + ParserState& state = this->GetState(); + + auto const it = state.Bindings.Keywords.Find(arg); + if (it != state.Bindings.Keywords.end()) { this->FinishKeyword(); - this->Keyword = it->first; - this->KeywordValuesSeen = 0; - this->DoneWithPositional = true; - if (this->Bindings.ParsedKeyword) { - this->Bindings.ParsedKeyword(*this, it->first); + state.Keyword = it->first; + state.KeywordValuesSeen = 0; + state.DoneWithPositional = true; + if (state.Bindings.ParsedKeyword) { + state.Bindings.ParsedKeyword(*this, it->first); } it->second(*this); return; } - if (!this->DoneWithPositional) { - auto const pit = this->Bindings.Positions.Find(pos); - if (pit != this->Bindings.Positions.end()) { - pit->second(*this, pos, arg); + if (!state.DoneWithPositional) { + auto const pit = state.Bindings.Positions.Find(state.Pos); + if (pit != state.Bindings.Positions.end()) { + pit->second(*this, state.Pos, arg); return; } - if (this->Bindings.TrailingArgs) { - this->Keyword = ""_s; - this->KeywordValuesSeen = 0; - this->DoneWithPositional = true; - this->Bindings.TrailingArgs(*this); - if (!this->KeywordValueFunc) { + if (state.Bindings.TrailingArgs) { + state.Keyword = ""_s; + state.KeywordValuesSeen = 0; + state.DoneWithPositional = true; + state.Bindings.TrailingArgs(*this); + if (!state.KeywordValueFunc) { return; } } } - if (this->KeywordValueFunc) { - switch (this->KeywordValueFunc(arg)) { + if (state.KeywordValueFunc) { + switch (state.KeywordValueFunc(arg)) { case Continue::Yes: break; case Continue::No: - this->KeywordValueFunc = nullptr; + state.KeywordValueFunc = nullptr; break; } - ++this->KeywordValuesSeen; + ++state.KeywordValuesSeen; return; } @@ -184,16 +186,18 @@ void Instance::Consume(std::size_t pos, cm::string_view arg) void Instance::FinishKeyword() { - if (!this->DoneWithPositional) { + ParserState& state = this->GetState(); + + if (state.DoneWithPositional) { return; } - if (this->KeywordValuesSeen < this->KeywordValuesExpected) { + if (state.KeywordValuesSeen < state.KeywordValuesExpected) { if (this->ParseResults) { - this->ParseResults->AddKeywordError(this->Keyword, + this->ParseResults->AddKeywordError(state.Keyword, " missing required value\n"); } - if (this->Bindings.KeywordMissingValue) { - this->Bindings.KeywordMissingValue(*this, this->Keyword); + if (state.Bindings.KeywordMissingValue) { + state.Bindings.KeywordMissingValue(*this, state.Keyword); } } } diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 223c3ce699..69a3377fe7 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -165,18 +165,40 @@ public: } }; +class ParserState +{ +public: + cm::string_view Keyword; + std::size_t Pos = 0; + std::size_t KeywordValuesSeen = 0; + std::size_t KeywordValuesExpected = 0; + std::function KeywordValueFunc = nullptr; + + ActionMap const& Bindings; + void* Result = nullptr; + bool DoneWithPositional = false; + + ParserState(ActionMap const& bindings, void* result) + : Bindings(bindings) + , Result(result) + { + } +}; + class Instance { public: Instance(ActionMap const& bindings, ParseResult* parseResult, std::vector* unparsedArguments, void* result = nullptr) - : Bindings(bindings) + + : ParseState(bindings, result) , ParseResults(parseResult) , UnparsedArguments(unparsedArguments) - , Result(result) { } + ParserState& GetState() { return ParseState; } + void Bind(std::function f, ExpectAtLeast expect); void Bind(bool& val); void Bind(std::string& val); @@ -219,25 +241,22 @@ public: template void Parse(Range const& args, std::size_t pos = 0) { - for (cm::string_view arg : args) { - this->Consume(pos++, arg); + GetState().Pos = pos; + + for (cm::string_view const arg : args) { + this->Consume(arg); + GetState().Pos++; } + this->FinishKeyword(); } private: - ActionMap const& Bindings; + ParserState ParseState; ParseResult* ParseResults = nullptr; std::vector* UnparsedArguments = nullptr; - void* Result = nullptr; - cm::string_view Keyword; - std::size_t KeywordValuesSeen = 0; - std::size_t KeywordValuesExpected = 0; - std::function KeywordValueFunc; - bool DoneWithPositional = false; - - void Consume(std::size_t pos, cm::string_view arg); + void Consume(cm::string_view arg); void FinishKeyword(); template @@ -259,7 +278,7 @@ public: cmArgumentParser& Bind(cm::static_string_view name, T member) { this->Base::Bind(name, [member](Instance& instance) { - instance.Bind(static_cast(instance.Result)->*member); + instance.Bind(static_cast(instance.GetState().Result)->*member); }); return *this; } @@ -269,7 +288,7 @@ public: T Result::*member, U Result::*context) { this->Base::Bind(name, [member, context](Instance& instance) { - auto* result = static_cast(instance.Result); + auto* result = static_cast(instance.GetState().Result); instance.Bind(result->*member, result->*context); }); return *this; @@ -280,7 +299,7 @@ public: ExpectAtLeast expect = { 1 }) { this->Base::Bind(name, [member, expect](Instance& instance) { - Result* result = static_cast(instance.Result); + Result* result = static_cast(instance.GetState().Result); instance.Bind( [result, member](cm::string_view arg) -> Continue { return (result->*member)(arg); @@ -296,8 +315,8 @@ public: ExpectAtLeast expect = { 1 }) { this->Base::Bind(name, [member, expect](Instance& instance) { - Result* result = static_cast(instance.Result); - cm::string_view keyword = instance.Keyword; + Result* result = static_cast(instance.GetState().Result); + cm::string_view keyword = instance.GetState().Keyword; instance.Bind( [result, member, keyword](cm::string_view arg) -> Continue { return (result->*member)(keyword, arg); @@ -312,7 +331,7 @@ public: ExpectAtLeast expect = { 1 }) { this->Base::Bind(name, [f, expect](Instance& instance) { - Result* result = static_cast(instance.Result); + Result* result = static_cast(instance.GetState().Result); instance.Bind( [result, &f](cm::string_view arg) -> Continue { return f(*result, arg); @@ -328,8 +347,8 @@ public: ExpectAtLeast expect = { 1 }) { this->Base::Bind(name, [f, expect](Instance& instance) { - Result* result = static_cast(instance.Result); - cm::string_view keyword = instance.Keyword; + Result* result = static_cast(instance.GetState().Result); + cm::string_view keyword = instance.GetState().Keyword; instance.Bind( [result, keyword, &f](cm::string_view arg) -> Continue { return f(*result, keyword, arg); @@ -345,7 +364,7 @@ public: this->Base::Bind( position, [member](Instance& instance, std::size_t, cm::string_view arg) { - Result* result = static_cast(instance.Result); + Result* result = static_cast(instance.GetState().Result); result->*member = arg; }); return *this; @@ -356,7 +375,8 @@ public: { this->Base::BindParsedKeyword( [member](Instance& instance, cm::string_view arg) { - (static_cast(instance.Result)->*member).emplace_back(arg); + (static_cast(instance.GetState().Result)->*member) + .emplace_back(arg); }); return *this; } @@ -368,7 +388,7 @@ public: cmArgumentParser& BindTrailingArgs(T member) { this->Base::BindTrailingArgs([member](Instance& instance) { - instance.Bind(static_cast(instance.Result)->*member); + instance.Bind(static_cast(instance.GetState().Result)->*member); }); return *this; } @@ -429,7 +449,7 @@ public: ExpectAtLeast expect = { 1 }) { this->Base::Bind(name, [f, expect](Instance& instance) { - cm::string_view keyword = instance.Keyword; + cm::string_view keyword = instance.GetState().Keyword; instance.Bind( [keyword, &f](cm::string_view arg) -> Continue { return f(keyword, arg);