1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmArgumentParser.h"
7 #include "cmArgumentParserTypes.h"
8 #include "cmMakefile.h"
9 #include "cmMessageType.h"
10 #include "cmStringAlgorithms.h"
12 namespace ArgumentParser {
14 auto KeywordActionMap::Emplace(cm::string_view name, KeywordAction action)
15 -> std::pair<iterator, bool>
18 std::lower_bound(this->begin(), this->end(), name,
19 [](value_type const& elem, cm::string_view const& k) {
20 return elem.first < k;
22 return (it != this->end() && it->first == name)
23 ? std::make_pair(it, false)
24 : std::make_pair(this->emplace(it, name, std::move(action)), true);
27 auto KeywordActionMap::Find(cm::string_view name) const -> const_iterator
30 std::lower_bound(this->begin(), this->end(), name,
31 [](value_type const& elem, cm::string_view const& k) {
32 return elem.first < k;
34 return (it != this->end() && it->first == name) ? it : this->end();
37 auto PositionActionMap::Emplace(std::size_t pos, PositionAction action)
38 -> std::pair<iterator, bool>
40 auto const it = std::lower_bound(
41 this->begin(), this->end(), pos,
42 [](value_type const& elem, std::size_t k) { return elem.first < k; });
43 return (it != this->end() && it->first == pos)
44 ? std::make_pair(it, false)
45 : std::make_pair(this->emplace(it, pos, std::move(action)), true);
48 auto PositionActionMap::Find(std::size_t pos) const -> const_iterator
50 auto const it = std::lower_bound(
51 this->begin(), this->end(), pos,
52 [](value_type const& elem, std::size_t k) { return elem.first < k; });
53 return (it != this->end() && it->first == pos) ? it : this->end();
56 void Instance::Bind(std::function<Continue(cm::string_view)> f,
59 this->KeywordValueFunc = std::move(f);
60 this->KeywordValuesExpected = expect.Count;
63 void Instance::Bind(bool& val)
66 this->Bind(nullptr, ExpectAtLeast{ 0 });
69 void Instance::Bind(std::string& val)
72 [&val](cm::string_view arg) -> Continue {
73 val = std::string(arg);
79 void Instance::Bind(NonEmpty<std::string>& val)
82 [this, &val](cm::string_view arg) -> Continue {
83 if (arg.empty() && this->ParseResults) {
84 this->ParseResults->AddKeywordError(this->Keyword,
85 " empty string not allowed\n");
87 val.assign(std::string(arg));
93 void Instance::Bind(Maybe<std::string>& val)
96 [&val](cm::string_view arg) -> Continue {
97 static_cast<std::string&>(val) = std::string(arg);
103 void Instance::Bind(MaybeEmpty<std::vector<std::string>>& val)
106 [&val](cm::string_view arg) -> Continue {
107 val.emplace_back(arg);
108 return Continue::Yes;
113 void Instance::Bind(NonEmpty<std::vector<std::string>>& val)
116 [&val](cm::string_view arg) -> Continue {
117 val.emplace_back(arg);
118 return Continue::Yes;
123 void Instance::Bind(std::vector<std::vector<std::string>>& multiVal)
125 multiVal.emplace_back();
126 std::vector<std::string>& val = multiVal.back();
128 [&val](cm::string_view arg) -> Continue {
129 val.emplace_back(arg);
130 return Continue::Yes;
135 void Instance::Consume(std::size_t pos, cm::string_view arg)
137 auto const it = this->Bindings.Keywords.Find(arg);
138 if (it != this->Bindings.Keywords.end()) {
139 this->FinishKeyword();
140 this->Keyword = it->first;
141 this->KeywordValuesSeen = 0;
142 this->DoneWithPositional = true;
143 if (this->Bindings.ParsedKeyword) {
144 this->Bindings.ParsedKeyword(*this, it->first);
150 if (this->KeywordValueFunc) {
151 switch (this->KeywordValueFunc(arg)) {
155 this->KeywordValueFunc = nullptr;
158 ++this->KeywordValuesSeen;
162 if (!this->DoneWithPositional) {
163 auto const pit = this->Bindings.Positions.Find(pos);
164 if (pit != this->Bindings.Positions.end()) {
165 pit->second(*this, pos, arg);
170 if (this->UnparsedArguments != nullptr) {
171 this->UnparsedArguments->emplace_back(arg);
175 void Instance::FinishKeyword()
177 if (this->Keyword.empty()) {
180 if (this->KeywordValuesSeen < this->KeywordValuesExpected) {
181 if (this->ParseResults != nullptr) {
182 this->ParseResults->AddKeywordError(this->Keyword,
183 " missing required value\n");
185 if (this->Bindings.KeywordMissingValue) {
186 this->Bindings.KeywordMissingValue(*this, this->Keyword);
191 bool ParseResult::MaybeReportError(cmMakefile& mf) const
197 for (auto const& ke : this->KeywordErrors) {
198 e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second);
200 mf.IssueMessage(MessageType::FATAL_ERROR, e);
204 } // namespace ArgumentParser