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