1 // 2 // docopt_private.h 3 // docopt 4 // 5 // Created by Jared Grubb on 2013-11-04. 6 // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 // 8 9 #ifndef docopt_docopt_private_h 10 #define docopt_docopt_private_h 11 12 #include <vector> 13 #include <memory> 14 #include <unordered_set> 15 16 #include "docopt_value.h" 17 18 namespace docopt { 19 20 class Pattern; 21 class LeafPattern; 22 23 using PatternList = std::vector<std::shared_ptr<Pattern>>; 24 25 // Utility to use Pattern types in std hash-containers 26 struct PatternHasher { 27 template <typename P> operatorPatternHasher28 size_t operator()(std::shared_ptr<P> const& pattern) const { 29 return pattern->hash(); 30 } 31 template <typename P> operatorPatternHasher32 size_t operator()(P const* pattern) const { 33 return pattern->hash(); 34 } 35 template <typename P> operatorPatternHasher36 size_t operator()(P const& pattern) const { 37 return pattern.hash(); 38 } 39 }; 40 41 // Utility to use 'hash' as the equality operator as well in std containers 42 struct PatternPointerEquality { 43 template <typename P1, typename P2> operatorPatternPointerEquality44 bool operator()(std::shared_ptr<P1> const& p1, std::shared_ptr<P2> const& p2) const { 45 return p1->hash()==p2->hash(); 46 } 47 template <typename P1, typename P2> operatorPatternPointerEquality48 bool operator()(P1 const* p1, P2 const* p2) const { 49 return p1->hash()==p2->hash(); 50 } 51 }; 52 53 // A hash-set that uniques by hash value 54 using UniquePatternSet = std::unordered_set<std::shared_ptr<Pattern>, PatternHasher, PatternPointerEquality>; 55 56 57 class Pattern { 58 public: 59 // flatten out children, stopping descent when the given filter returns 'true' 60 virtual std::vector<Pattern*> flat(bool (*filter)(Pattern const*)) = 0; 61 62 // flatten out all children into a list of LeafPattern objects 63 virtual void collect_leaves(std::vector<LeafPattern*>&) = 0; 64 65 // flatten out all children into a list of LeafPattern objects 66 std::vector<LeafPattern*> leaves(); 67 68 // Attempt to find something in 'left' that matches this pattern's spec, and if so, move it to 'collected' 69 virtual bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const = 0; 70 71 virtual std::string const& name() const = 0; 72 hasValue()73 virtual bool hasValue() const { return false; } 74 75 virtual size_t hash() const = 0; 76 77 virtual ~Pattern() = default; 78 }; 79 80 class LeafPattern 81 : public Pattern { 82 public: 83 LeafPattern(std::string name, value v = {}) fName(std::move (name))84 : fName(std::move(name)), 85 fValue(std::move(v)) 86 {} 87 flat(bool (* filter)(Pattern const *))88 virtual std::vector<Pattern*> flat(bool (*filter)(Pattern const*)) override { 89 if (filter(this)) { 90 return { this }; 91 } 92 return {}; 93 } 94 collect_leaves(std::vector<LeafPattern * > & lst)95 virtual void collect_leaves(std::vector<LeafPattern*>& lst) override final { 96 lst.push_back(this); 97 } 98 99 virtual bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const override; 100 hasValue()101 virtual bool hasValue() const override { return static_cast<bool>(fValue); } 102 getValue()103 value const& getValue() const { return fValue; } setValue(value && v)104 void setValue(value&& v) { fValue = std::move(v); } 105 name()106 virtual std::string const& name() const override { return fName; } 107 hash()108 virtual size_t hash() const override { 109 size_t seed = typeid(*this).hash_code(); 110 hash_combine(seed, fName); 111 hash_combine(seed, fValue); 112 return seed; 113 } 114 115 protected: 116 virtual std::pair<size_t, std::shared_ptr<LeafPattern>> single_match(PatternList const&) const = 0; 117 118 private: 119 std::string fName; 120 value fValue; 121 }; 122 123 class BranchPattern 124 : public Pattern { 125 public: 126 BranchPattern(PatternList children = {}) fChildren(std::move (children))127 : fChildren(std::move(children)) 128 {} 129 fix()130 Pattern& fix() { 131 UniquePatternSet patterns; 132 fix_identities(patterns); 133 fix_repeating_arguments(); 134 return *this; 135 } 136 name()137 virtual std::string const& name() const override { 138 throw std::runtime_error("Logic error: name() shouldnt be called on a BranchPattern"); 139 } 140 getValue()141 virtual value const& getValue() const { 142 throw std::runtime_error("Logic error: name() shouldnt be called on a BranchPattern"); 143 } 144 flat(bool (* filter)(Pattern const *))145 virtual std::vector<Pattern*> flat(bool (*filter)(Pattern const*)) override { 146 if (filter(this)) { 147 return {this}; 148 } 149 150 std::vector<Pattern*> ret; 151 for(auto& child : fChildren) { 152 auto sublist = child->flat(filter); 153 ret.insert(ret.end(), sublist.begin(), sublist.end()); 154 } 155 return ret; 156 } 157 collect_leaves(std::vector<LeafPattern * > & lst)158 virtual void collect_leaves(std::vector<LeafPattern*>& lst) override final { 159 for(auto& child : fChildren) { 160 child->collect_leaves(lst); 161 } 162 } 163 setChildren(PatternList children)164 void setChildren(PatternList children) { 165 fChildren = std::move(children); 166 } 167 children()168 PatternList const& children() const { return fChildren; } 169 fix_identities(UniquePatternSet & patterns)170 virtual void fix_identities(UniquePatternSet& patterns) { 171 for(auto& child : fChildren) { 172 // this will fix up all its children, if needed 173 if (auto bp = dynamic_cast<BranchPattern*>(child.get())) { 174 bp->fix_identities(patterns); 175 } 176 177 // then we try to add it to the list 178 auto inserted = patterns.insert(child); 179 if (!inserted.second) { 180 // already there? then reuse the existing shared_ptr for that thing 181 child = *inserted.first; 182 } 183 } 184 } 185 hash()186 virtual size_t hash() const override { 187 size_t seed = typeid(*this).hash_code(); 188 hash_combine(seed, fChildren.size()); 189 for(auto const& child : fChildren) { 190 hash_combine(seed, child->hash()); 191 } 192 return seed; 193 } 194 private: 195 void fix_repeating_arguments(); 196 197 protected: 198 PatternList fChildren; 199 }; 200 201 class Argument 202 : public LeafPattern { 203 public: 204 using LeafPattern::LeafPattern; 205 206 protected: 207 virtual std::pair<size_t, std::shared_ptr<LeafPattern>> single_match(PatternList const& left) const override; 208 }; 209 210 class Command : public Argument { 211 public: 212 Command(std::string name, value v = value{false}) Argument(std::move (name),std::move (v))213 : Argument(std::move(name), std::move(v)) 214 {} 215 216 protected: 217 virtual std::pair<size_t, std::shared_ptr<LeafPattern>> single_match(PatternList const& left) const override; 218 }; 219 220 class Option final 221 : public LeafPattern 222 { 223 public: 224 static Option parse(std::string const& option_description); 225 226 Option(std::string shortOption, 227 std::string longOption, 228 int argcount = 0, 229 value v = value{false}) 230 : LeafPattern(longOption.empty() ? shortOption : longOption, 231 std::move(v)), 232 fShortOption(std::move(shortOption)), 233 fLongOption(std::move(longOption)), 234 fArgcount(argcount) 235 { 236 // From Python: 237 // self.value = None if value is False and argcount else value 238 if (argcount && v.isBool() && !v.asBool()) { 239 setValue(value{}); 240 } 241 } 242 243 Option(Option const&) = default; 244 Option(Option&&) = default; 245 Option& operator=(Option const&) = default; 246 Option& operator=(Option&&) = default; 247 248 using LeafPattern::setValue; 249 longOption()250 std::string const& longOption() const { return fLongOption; } shortOption()251 std::string const& shortOption() const { return fShortOption; } argCount()252 int argCount() const { return fArgcount; } 253 hash()254 virtual size_t hash() const override { 255 size_t seed = LeafPattern::hash(); 256 hash_combine(seed, fShortOption); 257 hash_combine(seed, fLongOption); 258 hash_combine(seed, fArgcount); 259 return seed; 260 } 261 262 protected: 263 virtual std::pair<size_t, std::shared_ptr<LeafPattern>> single_match(PatternList const& left) const override; 264 265 private: 266 std::string fShortOption; 267 std::string fLongOption; 268 int fArgcount; 269 }; 270 271 class Required : public BranchPattern { 272 public: 273 using BranchPattern::BranchPattern; 274 275 bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const override; 276 }; 277 278 class Optional : public BranchPattern { 279 public: 280 using BranchPattern::BranchPattern; 281 match(PatternList & left,std::vector<std::shared_ptr<LeafPattern>> & collected)282 bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const override { 283 for(auto const& pattern : fChildren) { 284 pattern->match(left, collected); 285 } 286 return true; 287 } 288 }; 289 290 class OptionsShortcut : public Optional { 291 using Optional::Optional; 292 }; 293 294 class OneOrMore : public BranchPattern { 295 public: 296 using BranchPattern::BranchPattern; 297 298 bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const override; 299 }; 300 301 class Either : public BranchPattern { 302 public: 303 using BranchPattern::BranchPattern; 304 305 bool match(PatternList& left, std::vector<std::shared_ptr<LeafPattern>>& collected) const override; 306 }; 307 } 308 309 #endif 310