diff --git a/docopt.cpp b/docopt.cpp index 2aed8a4..62d2690 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -47,7 +47,7 @@ void value::throwIfNotKind(Kind expected) const { if (kind == expected) return; - + std::string error = "Illegal cast to "; error += kindAsString(expected); error += "; type is actually "; @@ -98,7 +98,7 @@ bool Required::match(PatternList& left, std::vector { auto l = left; auto c = collected; - + for(auto const& pattern : fChildren) { bool ret = pattern->match(l, c); if (!ret) { @@ -106,7 +106,7 @@ bool Required::match(PatternList& left, std::vector return false; } } - + left = std::move(l); collected = std::move(c); return true; @@ -118,9 +118,9 @@ bool LeafPattern::match(PatternList& left, std::vector const& p) { return p->name()==name(); }); @@ -144,7 +144,7 @@ bool LeafPattern::match(PatternList& left, std::vectorsetValue(value{val}); @@ -166,14 +166,14 @@ Option Option::parse(std::string const& option_description) std::string shortOption, longOption; int argcount = 0; value val { false }; - + auto double_space = option_description.find(" "); auto options_end = option_description.end(); if (double_space != std::string::npos) { options_end = option_description.begin() + double_space; } - - static const std::regex pattern {"(--|-)?(.*?)([,= ]|$)"}; + + static const std::regex pattern {"(-{1,2})?(.*?)([,= ]|$)"}; for(std::sregex_iterator i {option_description.begin(), options_end, pattern, std::regex_constants::match_not_null}, e{}; i != e; @@ -182,9 +182,9 @@ Option Option::parse(std::string const& option_description) std::smatch const& match = *i; if (match[1].matched) { // [1] is optional. if (match[1].length()==1) { - shortOption = "-" + match[2].str(); + shortOption = "-" + match[2].str(); } else { - longOption = "--" + match[2].str(); + longOption = "--" + match[2].str(); } } else if (match[2].length() > 0) { // [2] always matches. std::string m = match[2]; @@ -210,7 +210,7 @@ Option Option::parse(std::string const& option_description) val = match[1].str(); } } - + return {std::move(shortOption), std::move(longOption), argcount, @@ -220,36 +220,36 @@ Option Option::parse(std::string const& option_description) bool OneOrMore::match(PatternList& left, std::vector>& collected) const { assert(fChildren.size() == 1); - + auto l = left; auto c = collected; - + bool matched = true; size_t times = 0; - + decltype(l) l_; bool firstLoop = true; - + while (matched) { // could it be that something didn't match but changed l or c? matched = fChildren[0]->match(l, c); - + if (matched) ++times; - + if (firstLoop) { firstLoop = false; } else if (l == l_) { break; } - + l_ = l; } - + if (times == 0) { return false; } - + left = std::move(l); collected = std::move(c); return true; @@ -258,9 +258,9 @@ bool OneOrMore::match(PatternList& left, std::vector>& collected) const { using Outcome = std::pair>>; - + std::vector outcomes; - + for(auto const& pattern : fChildren) { // need a copy so we apply the same one for every iteration auto l = left; @@ -270,16 +270,16 @@ bool Either::match(PatternList& left, std::vector>& outcomes.emplace_back(std::move(l), std::move(c)); } } - + auto min = std::min_element(outcomes.begin(), outcomes.end(), [](Outcome const& o1, Outcome const& o2) { return o1.first.size() < o2.first.size(); }); - + if (min == outcomes.end()) { // (left, collected) unchanged return false; } - + std::tie(left, collected) = std::move(*min); return true; } @@ -287,7 +287,7 @@ bool Either::match(PatternList& left, std::vector>& std::pair> Argument::single_match(PatternList const& left) const { std::pair> ret {}; - + for(size_t i = 0, size = left.size(); i < size; ++i) { auto arg = dynamic_cast(left[i].get()); @@ -297,14 +297,14 @@ std::pair> Argument::single_match(PatternLi break; } } - + return ret; } std::pair> Command::single_match(PatternList const& left) const { std::pair> ret {}; - + for(size_t i = 0, size = left.size(); i < size; ++i) { auto arg = dynamic_cast(left[i].get()); @@ -316,14 +316,14 @@ std::pair> Command::single_match(PatternLis break; } } - + return ret; } std::pair> Option::single_match(PatternList const& left) const { std::pair> ret {}; - + for(size_t i = 0, size = left.size(); i < size; ++i) { auto leaf = std::dynamic_pointer_cast(left[i]); @@ -333,7 +333,7 @@ std::pair> Option::single_match(PatternList break; } } - + return ret; } @@ -351,13 +351,13 @@ void BranchPattern::fix_repeating_arguments() for(auto const& e : group_set) { if (group_set.count(e) == 1) continue; - + LeafPattern* leaf = dynamic_cast(e.get()); if (!leaf) continue; - + bool ensureList = false; bool ensureInt = false; - + if (dynamic_cast(leaf)) { ensureInt = true; } else if (dynamic_cast(leaf)) { @@ -369,7 +369,7 @@ void BranchPattern::fix_repeating_arguments() ensureInt = true; } } - + if (ensureList) { std::vector newValue; if (leaf->getValue().isString()) { @@ -388,37 +388,37 @@ void BranchPattern::fix_repeating_arguments() std::vector transform(PatternList pattern) { std::vector result; - + std::vector groups; groups.emplace_back(std::move(pattern)); - + while(!groups.empty()) { // pop off the first element auto children = std::move(groups[0]); groups.erase(groups.begin()); - + // find the first branch node in the list auto child_iter = std::find_if(children.begin(), children.end(), [](std::shared_ptr const& p) { return dynamic_cast(p.get()); }); - + // no branch nodes left : expansion is complete for this grouping if (child_iter == children.end()) { result.emplace_back(std::move(children)); continue; } - + // pop the child from the list auto child = std::move(*child_iter); children.erase(child_iter); - + // expand the branch in the appropriate way if (Either* either = dynamic_cast(child.get())) { // "[e] + children" for each child 'e' in Either for(auto const& eitherChild : either->children()) { PatternList group = { eitherChild }; group.insert(group.end(), children.begin(), children.end()); - + groups.emplace_back(std::move(group)); } } else if (OneOrMore* oneOrMore = dynamic_cast(child.get())) { @@ -427,19 +427,19 @@ std::vector transform(PatternList pattern) PatternList group = subchildren; group.insert(group.end(), subchildren.begin(), subchildren.end()); group.insert(group.end(), children.begin(), children.end()); - + groups.emplace_back(std::move(group)); } else { // Required, Optional, OptionsShortcut BranchPattern* branch = dynamic_cast(child.get()); - + // child.children + children PatternList group = branch->children(); group.insert(group.end(), children.begin(), children.end()); - + groups.emplace_back(std::move(group)); } } - + return result; } @@ -449,11 +449,11 @@ class Tokens { : fTokens(std::move(tokens)), fIsParsingArgv(isParsingArgv) {} - + explicit operator bool() const { return fIndex < fTokens.size(); } - + static Tokens from_pattern(std::string const& source) { static const std::regex re_separators { "(?:\\s*)" // any spaces (non-matching subgroup) @@ -462,21 +462,21 @@ class Tokens { "|" "\\.\\.\\." // elipsis ")" }; - + static const std::regex re_strings { "(?:\\s*)" // any spaces (non-matching subgroup) "(" "\\S*<.*?>" // strings, but make sure to keep "< >" strings together "|" - "\\S+" // string without <> + "[^<>\\s]+" // string without <> ")" }; - + // We do two stages of regex matching. The '[]()' and '...' are strong delimeters // and need to be split out anywhere they occur (even at the end of a token). We // first split on those, and then parse the stuff between them to find the string // tokens. This is a little harder than the python version, since they have regex.split // and we dont have anything like that. - + std::vector tokens; std::for_each(std::sregex_iterator{ source.begin(), source.end(), re_separators }, std::sregex_iterator{}, @@ -491,24 +491,24 @@ class Tokens { tokens.push_back(m[1].str()); }); } - + // handle the delimter token itself if (match[1].matched) { tokens.push_back(match[1].str()); } }); - + return Tokens(tokens, false); } - + std::string const& current() const { if (*this) return fTokens[fIndex]; - + static std::string const empty; return empty; } - + std::string the_rest() const { if (!*this) return {}; @@ -516,28 +516,28 @@ class Tokens { fTokens.end(), " "); } - + std::string pop() { return std::move(fTokens.at(fIndex++)); } - + bool isParsingArgv() const { return fIsParsingArgv; } - + struct OptionError : std::runtime_error { using runtime_error::runtime_error; }; - + private: std::vector fTokens; size_t fIndex = 0; bool fIsParsingArgv; }; - + // Get all instances of 'T' from the pattern template std::vector flat_filter(Pattern& pattern) { std::vector flattened = pattern.flat([](Pattern const* p) -> bool { return dynamic_cast(p); }); - + // now, we're guaranteed to have T*'s, so just use static_cast std::vector ret; std::transform(flattened.begin(), flattened.end(), std::back_inserter(ret), [](Pattern* p) { @@ -559,7 +559,7 @@ std::vector parse_section(std::string const& name, std::string cons ")", std::regex::icase }; - + std::vector ret; std::for_each(std::sregex_iterator(source.begin(), source.end(), re_section_pattern), std::sregex_iterator(), @@ -567,20 +567,20 @@ std::vector parse_section(std::string const& name, std::string cons { ret.push_back(trim(match[1].str())); }); - + return ret; } bool is_argument_spec(std::string const& token) { if (token.empty()) return false; - + if (token[0]=='<' && token[token.size()-1]=='>') return true; - + if (std::all_of(token.begin(), token.end(), &::isupper)) return true; - + return false; } @@ -599,20 +599,20 @@ PatternList parse_long(Tokens& tokens, std::vector