6
6
// Copyright (c) 2013 Jared Grubb. All rights reserved.
7
7
//
8
8
9
+ #define NO_RAW_FOR_LOOPS 0
10
+
9
11
#include " docopt.h"
10
12
#include " docopt_util.h"
11
13
#include " docopt_private.h"
24
26
25
27
using namespace docopt ;
26
28
27
- DocoptExitHelp::DocoptExitHelp ()
28
- : std::runtime_error(" Docopt --help argument encountered" )
29
- {}
30
-
31
- DocoptExitVersion::DocoptExitVersion ()
32
- : std::runtime_error(" Docopt --version argument encountered" )
33
- {}
34
-
35
- const char * value::kindAsString (Kind kind)
36
- {
37
- switch (kind) {
38
- case Kind::Empty: return " empty" ;
39
- case Kind::Bool: return " bool" ;
40
- case Kind::Long: return " long" ;
41
- case Kind::String: return " string" ;
42
- case Kind::StringList: return " string-list" ;
43
- }
44
- return " unknown" ;
45
- }
46
-
47
- void value::throwIfNotKind (Kind expected) const
48
- {
49
- if (kind == expected)
50
- return ;
51
-
52
- std::string error = " Illegal cast to " ;
53
- error += kindAsString (expected);
54
- error += " ; type is actually " ;
55
- error += kindAsString (kind);
56
- throw std::runtime_error (std::move (error));
57
- }
58
-
59
29
std::ostream& docopt::operator <<(std::ostream& os, value const & val)
60
30
{
61
31
if (val.isBool ()) {
@@ -89,255 +59,6 @@ std::ostream& docopt::operator<<(std::ostream& os, value const& val)
89
59
#pragma mark -
90
60
#pragma mark Pattern types
91
61
92
- std::vector<LeafPattern*> Pattern::leaves () {
93
- std::vector<LeafPattern*> ret;
94
- collect_leaves (ret);
95
- return ret;
96
- }
97
-
98
- bool Required::match (PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const
99
- {
100
- auto l = left;
101
- auto c = collected;
102
-
103
- for (auto const & pattern : fChildren ) {
104
- bool ret = pattern->match (l, c);
105
- if (!ret) {
106
- // leave (left, collected) untouched
107
- return false ;
108
- }
109
- }
110
-
111
- left = std::move (l);
112
- collected = std::move (c);
113
- return true ;
114
- }
115
-
116
- bool LeafPattern::match (PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const
117
- {
118
- auto match = single_match (left);
119
- if (!match.second ) {
120
- return false ;
121
- }
122
-
123
- left.erase (left.begin ()+static_cast <std::ptrdiff_t >(match.first ));
124
-
125
- auto same_name = std::find_if (collected.begin (), collected.end (), [&](std::shared_ptr<LeafPattern> const & p) {
126
- return p->name ()==name ();
127
- });
128
- if (getValue ().isLong ()) {
129
- long val = 1 ;
130
- if (same_name == collected.end ()) {
131
- collected.push_back (match.second );
132
- match.second ->setValue (value{val});
133
- } else if ((**same_name).getValue ().isLong ()) {
134
- val += (**same_name).getValue ().asLong ();
135
- (**same_name).setValue (value{val});
136
- } else {
137
- (**same_name).setValue (value{val});
138
- }
139
- } else if (getValue ().isStringList ()) {
140
- std::vector<std::string> val;
141
- if (match.second ->getValue ().isString ()) {
142
- val.push_back (match.second ->getValue ().asString ());
143
- } else if (match.second ->getValue ().isStringList ()) {
144
- val = match.second ->getValue ().asStringList ();
145
- } else {
146
- // / cant be!?
147
- }
148
-
149
- if (same_name == collected.end ()) {
150
- collected.push_back (match.second );
151
- match.second ->setValue (value{val});
152
- } else if ((**same_name).getValue ().isStringList ()) {
153
- std::vector<std::string> const & list = (**same_name).getValue ().asStringList ();
154
- val.insert (val.begin (), list.begin (), list.end ());
155
- (**same_name).setValue (value{val});
156
- } else {
157
- (**same_name).setValue (value{val});
158
- }
159
- } else {
160
- collected.push_back (match.second );
161
- }
162
- return true ;
163
- }
164
-
165
- Option Option::parse (std::string const & option_description)
166
- {
167
- std::string shortOption, longOption;
168
- int argcount = 0 ;
169
- value val { false };
170
-
171
- auto double_space = option_description.find (" " );
172
- auto options_end = option_description.end ();
173
- if (double_space != std::string::npos) {
174
- options_end = option_description.begin () + static_cast <std::ptrdiff_t >(double_space);
175
- }
176
-
177
- static const std::regex pattern {" (-{1,2})?(.*?)([,= ]|$)" };
178
- for (std::sregex_iterator i {option_description.begin (), options_end, pattern, std::regex_constants::match_not_null},
179
- e{};
180
- i != e;
181
- ++i)
182
- {
183
- std::smatch const & match = *i;
184
- if (match[1 ].matched ) { // [1] is optional.
185
- if (match[1 ].length ()==1 ) {
186
- shortOption = " -" + match[2 ].str ();
187
- } else {
188
- longOption = " --" + match[2 ].str ();
189
- }
190
- } else if (match[2 ].length () > 0 ) { // [2] always matches.
191
- std::string m = match[2 ];
192
- argcount = 1 ;
193
- } else {
194
- // delimeter
195
- }
196
-
197
- if (match[3 ].length () == 0 ) { // [3] always matches.
198
- // Hit end of string. For some reason 'match_not_null' will let us match empty
199
- // at the end, and then we'll spin in an infinite loop. So, if we hit an empty
200
- // match, we know we must be at the end.
201
- break ;
202
- }
203
- }
204
-
205
- if (argcount) {
206
- std::smatch match;
207
- if (std::regex_search (options_end, option_description.end (),
208
- match,
209
- std::regex{" \\ [default: (.*)\\ ]" , std::regex::icase}))
210
- {
211
- val = match[1 ].str ();
212
- }
213
- }
214
-
215
- return {std::move (shortOption),
216
- std::move (longOption),
217
- argcount,
218
- std::move (val)};
219
- }
220
-
221
- bool OneOrMore::match (PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const
222
- {
223
- assert (fChildren .size () == 1 );
224
-
225
- auto l = left;
226
- auto c = collected;
227
-
228
- bool matched = true ;
229
- size_t times = 0 ;
230
-
231
- decltype (l) l_;
232
- bool firstLoop = true ;
233
-
234
- while (matched) {
235
- // could it be that something didn't match but changed l or c?
236
- matched = fChildren [0 ]->match (l, c);
237
-
238
- if (matched)
239
- ++times;
240
-
241
- if (firstLoop) {
242
- firstLoop = false ;
243
- } else if (l == l_) {
244
- break ;
245
- }
246
-
247
- l_ = l;
248
- }
249
-
250
- if (times == 0 ) {
251
- return false ;
252
- }
253
-
254
- left = std::move (l);
255
- collected = std::move (c);
256
- return true ;
257
- }
258
-
259
- bool Either::match (PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const
260
- {
261
- using Outcome = std::pair<PatternList, std::vector<std::shared_ptr<LeafPattern>>>;
262
-
263
- std::vector<Outcome> outcomes;
264
-
265
- for (auto const & pattern : fChildren ) {
266
- // need a copy so we apply the same one for every iteration
267
- auto l = left;
268
- auto c = collected;
269
- bool matched = pattern->match (l, c);
270
- if (matched) {
271
- outcomes.emplace_back (std::move (l), std::move (c));
272
- }
273
- }
274
-
275
- auto min = std::min_element (outcomes.begin (), outcomes.end (), [](Outcome const & o1, Outcome const & o2) {
276
- return o1.first .size () < o2.first .size ();
277
- });
278
-
279
- if (min == outcomes.end ()) {
280
- // (left, collected) unchanged
281
- return false ;
282
- }
283
-
284
- std::tie (left, collected) = std::move (*min);
285
- return true ;
286
- }
287
-
288
- std::pair<size_t , std::shared_ptr<LeafPattern>> Argument::single_match (PatternList const & left) const
289
- {
290
- std::pair<size_t , std::shared_ptr<LeafPattern>> ret {};
291
-
292
- for (size_t i = 0 , size = left.size (); i < size; ++i)
293
- {
294
- auto arg = dynamic_cast <Argument const *>(left[i].get ());
295
- if (arg) {
296
- ret.first = i;
297
- ret.second = std::make_shared<Argument>(name (), arg->getValue ());
298
- break ;
299
- }
300
- }
301
-
302
- return ret;
303
- }
304
-
305
- std::pair<size_t , std::shared_ptr<LeafPattern>> Command::single_match (PatternList const & left) const
306
- {
307
- std::pair<size_t , std::shared_ptr<LeafPattern>> ret {};
308
-
309
- for (size_t i = 0 , size = left.size (); i < size; ++i)
310
- {
311
- auto arg = dynamic_cast <Argument const *>(left[i].get ());
312
- if (arg) {
313
- if (name () == arg->getValue ()) {
314
- ret.first = i;
315
- ret.second = std::make_shared<Command>(name (), value{true });
316
- }
317
- break ;
318
- }
319
- }
320
-
321
- return ret;
322
- }
323
-
324
- std::pair<size_t , std::shared_ptr<LeafPattern>> Option::single_match (PatternList const & left) const
325
- {
326
- std::pair<size_t , std::shared_ptr<LeafPattern>> ret {};
327
-
328
- for (size_t i = 0 , size = left.size (); i < size; ++i)
329
- {
330
- auto leaf = std::dynamic_pointer_cast<LeafPattern>(left[i]);
331
- if (leaf && name () == leaf->name ()) {
332
- ret.first = i;
333
- ret.second = leaf;
334
- break ;
335
- }
336
- }
337
-
338
- return ret;
339
- }
340
-
341
62
#pragma mark -
342
63
#pragma mark Parsing stuff
343
64
@@ -803,20 +524,13 @@ static PatternList parse_seq(Tokens& tokens, std::vector<Option>& options)
803
524
return ret;
804
525
}
805
526
806
- static std::shared_ptr<Pattern> maybe_collapse_to_required (PatternList&& seq)
807
- {
808
- if (seq.size ()==1 ) {
809
- return std::move (seq[0 ]);
810
- }
811
- return std::make_shared<Required>(std::move (seq));
812
- }
813
-
814
- static std::shared_ptr<Pattern> maybe_collapse_to_either (PatternList&& seq)
527
+ template <typename Which>
528
+ std::shared_ptr<Pattern> maybe_collapse_to (PatternList&& seq)
815
529
{
816
530
if (seq.size ()==1 ) {
817
531
return std::move (seq[0 ]);
818
532
}
819
- return std::make_shared<Either >(std::move (seq));
533
+ return std::make_shared<Which >(std::move (seq));
820
534
}
821
535
822
536
PatternList parse_expr (Tokens& tokens, std::vector<Option>& options)
@@ -829,15 +543,15 @@ PatternList parse_expr(Tokens& tokens, std::vector<Option>& options)
829
543
return seq;
830
544
831
545
PatternList ret;
832
- ret.emplace_back (maybe_collapse_to_required (std::move (seq)));
546
+ ret.emplace_back (maybe_collapse_to<Required> (std::move (seq)));
833
547
834
548
while (tokens.current () == " |" ) {
835
549
tokens.pop ();
836
550
seq = parse_seq (tokens, options);
837
- ret.emplace_back (maybe_collapse_to_required (std::move (seq)));
551
+ ret.emplace_back (maybe_collapse_to<Required> (std::move (seq)));
838
552
}
839
553
840
- return { maybe_collapse_to_either (std::move (ret)) };
554
+ return { maybe_collapse_to<Either> (std::move (ret)) };
841
555
}
842
556
843
557
static Required parse_pattern (std::string const & source, std::vector<Option>& options)
@@ -1001,6 +715,7 @@ static std::pair<Required, std::vector<Option>> create_pattern_tree(std::string
1001
715
return { std::move (pattern), std::move (options) };
1002
716
}
1003
717
718
+ DOCOPT_INLINE
1004
719
std::map<std::string, value>
1005
720
docopt::docopt_parse (std::string const & doc,
1006
721
std::vector<std::string> const & argv,
@@ -1050,6 +765,7 @@ docopt::docopt_parse(std::string const& doc,
1050
765
throw DocoptArgumentError (" Arguments did not match expected patterns" ); // BLEH. Bad error.
1051
766
}
1052
767
768
+ DOCOPT_INLINE
1053
769
std::map<std::string, value>
1054
770
docopt::docopt (std::string const & doc,
1055
771
std::vector<std::string> const & argv,
0 commit comments