1 /*
2 Copyright (C) 2017-2018 by the Battle for Wesnoth Project https://www.wesnoth.org/
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY.
10
11 See the COPYING file for more details.
12 */
13
14 #pragma once
15
16 #include "exceptions.hpp"
17 #include "formula/callable_fwd.hpp"
18 #include "utils/general.hpp"
19 #include "utils/make_enum.hpp"
20
21 #include <functional>
22 #include <iostream>
23 #include <iterator>
24 #include <map>
25 #include <sstream>
26 #include <utility>
27 #include <vector>
28 #include <boost/range/iterator_range.hpp>
29 #include <boost/any.hpp>
30
31 namespace wfl
32 {
33 class variant_value_base;
34 class variant_iterator;
35 class variant;
36
37 /** The various types the variant class is designed to handle */
38 MAKE_ENUM(VARIANT_TYPE,
39 (TYPE_NULL, "null")
40 (TYPE_INT, "int")
41 (TYPE_DECIMAL, "decimal")
42 (TYPE_CALLABLE, "object")
43 (TYPE_LIST, "list")
44 (TYPE_STRING, "string")
45 (TYPE_MAP, "map")
46 );
47
48 using variant_vector = std::vector<variant>;
49 using variant_map_raw = std::map<variant, variant>;
50 using value_base_ptr = std::shared_ptr<variant_value_base>;
51
52 struct type_error : public game::error
53 {
54 explicit type_error(const std::string& str);
55 };
56
57 /** Casts a @ref variant_value_base shared pointer to a new derived type. */
58 template<typename T>
value_cast(value_base_ptr ptr)59 static std::shared_ptr<T> value_cast(value_base_ptr ptr)
60 {
61 std::shared_ptr<T> res = std::dynamic_pointer_cast<T>(ptr);
62 if(!res) {
63 throw type_error("Could not cast type");
64 }
65
66 return res;
67 }
68
69 /** Casts a @ref variant_value_base reference to a new derived type. */
70 template<typename T>
value_ref_cast(variant_value_base & ptr)71 static T& value_ref_cast(variant_value_base& ptr)
72 {
73 try {
74 return dynamic_cast<T&>(ptr);
75 } catch(const std::bad_cast&) {
76 throw type_error("Could not cast type");
77 }
78 }
79
80 /**
81 * Base class for all variant types.
82 *
83 * This provides a common interface for all type classes to implement, as well as
84 * giving variant a base pointer type for its value member. It also serves as the
85 * implementation of the 'null' variant value.
86 *
87 * Do note this class should *not* implement any data members.
88 */
89 class variant_value_base
90 {
91 public:
92 /** Returns the number of elements in a type. Not relevant for every derivative. */
num_elements() const93 virtual size_t num_elements() const
94 {
95 return 0;
96 }
97
98 /** Whether the stored value is considered empty or not. */
is_empty() const99 virtual bool is_empty() const
100 {
101 return true;
102 }
103
104 /** Returns the stored variant value in plain string form. */
string_cast() const105 virtual std::string string_cast() const
106 {
107 return "0";
108 }
109
110 /** Returns the stored variant value in formula syntax. */
get_serialized_string() const111 virtual std::string get_serialized_string() const
112 {
113 return "null()";
114 }
115
116 /** Returns debug info for the variant value. */
get_debug_string(formula_seen_stack &,bool) const117 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const
118 {
119 return get_serialized_string();
120 }
121
122 /** Returns a bool expression of the variant value. */
as_bool() const123 virtual bool as_bool() const
124 {
125 return false;
126 }
127
128 /**
129 * Called to determine if this variant is equal to another _of the same type_.
130 * This function is _only_ called if get_type() returns the same result for both arguments.
131 */
equals(variant_value_base &) const132 virtual bool equals(variant_value_base& /*other*/) const
133 {
134 return true; // null is equal to null
135 }
136
137 /**
138 * Called to determine if this variant is less than another _of the same type_.
139 * This function is _only_ called if get_type() returns the same result for both arguments.
140 */
less_than(variant_value_base &) const141 virtual bool less_than(variant_value_base& /*other*/) const
142 {
143 return false; // null is not less than null
144 }
145
146 /** Returns the id of the variant type */
get_type() const147 virtual const VARIANT_TYPE& get_type() const
148 {
149 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_NULL;
150 return type;
151 }
152
153 /**
154 * Creates an iterator pair that can be used for iteration.
155 * For an iterable type, it should use the two-argument constructor of variant-iterator,
156 * passing the underlying iterator as the boost::any parameter.
157 *
158 * This creates both the begin and end iterator, but the variant implementation
159 * discards one of the two.
160 */
161 virtual boost::iterator_range<variant_iterator> make_iterator() const;
162
163 /**
164 * Implements the dereference functionality of @ref variant_iterator
165 * for a value of this type.
166 *
167 * @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
168 */
169 virtual variant deref_iterator(const boost::any& iter) const;
170
171 /**
172 * Implements the increment functionality of @ref variant_iterator
173 * for a value of this type.
174 *
175 * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
176 */
iterator_inc(boost::any &) const177 virtual void iterator_inc(boost::any&) const {}
178
179 /**
180 * Implements the decrement functionality of @ref variant_iterator
181 * for a value of this type.
182 *
183 * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
184 */
iterator_dec(boost::any &) const185 virtual void iterator_dec(boost::any&) const {}
186
187 /**
188 * Implements the equality functionality of @ref variant_iterator
189 * for a value of this type.
190 *
191 * Note that this is only called if the two iterators are already known to be of the same type.
192 *
193 * The first parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
194 * The second parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
195 */
iterator_equals(const boost::any &,const boost::any &) const196 virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const
197 {
198 return true;
199 }
200
~variant_value_base()201 virtual ~variant_value_base() {}
202 };
203
204
205 /**
206 * Base class for numeric variant values. Currently only supports a value stored as an
207 * integer, but for now, that's all that's necessary.
208 */
209 class variant_numeric : public variant_value_base
210 {
211 public:
variant_numeric(int value)212 explicit variant_numeric(int value) : value_(value) {}
213
as_bool() const214 virtual bool as_bool() const override
215 {
216 return value_ != 0;
217 }
218
get_numeric_value() const219 int get_numeric_value() const
220 {
221 return value_;
222 }
223
equals(variant_value_base & other) const224 virtual bool equals(variant_value_base& other) const override
225 {
226 return value_ == value_ref_cast<variant_numeric>(other).value_;
227 }
228
less_than(variant_value_base & other) const229 virtual bool less_than(variant_value_base& other) const override
230 {
231 return value_ < value_ref_cast<variant_numeric>(other).value_;
232 }
233
234 protected:
235 int value_;
236 };
237
238
239 class variant_int : public variant_numeric
240 {
241 public:
variant_int(int value)242 explicit variant_int(int value) : variant_numeric(value) {}
243
244 variant build_range_variant(int limit) const;
245
string_cast() const246 virtual std::string string_cast() const override
247 {
248 return std::to_string(value_);
249 }
250
get_serialized_string() const251 virtual std::string get_serialized_string() const override
252 {
253 return string_cast();
254 }
255
get_debug_string(formula_seen_stack &,bool) const256 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
257 {
258 return string_cast();
259 }
260
get_type() const261 virtual const VARIANT_TYPE& get_type() const override
262 {
263 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_INT;
264 return type;
265 }
266 };
267
268
269 class variant_decimal : public variant_numeric
270 {
271 public:
variant_decimal(int value)272 explicit variant_decimal(int value) : variant_numeric(value) {}
273
variant_decimal(double value)274 explicit variant_decimal(double value) : variant_numeric(0)
275 {
276 value *= 1000;
277 value_ = static_cast<int>(value);
278 value -= value_;
279
280 if(value > 0.5) {
281 value_++;
282 } else if(value < -0.5) {
283 value_--;
284 }
285 }
286
string_cast() const287 virtual std::string string_cast() const override
288 {
289 return to_string_impl(false);
290 }
291
get_serialized_string() const292 virtual std::string get_serialized_string() const override
293 {
294 return to_string_impl(false);
295 }
296
get_debug_string(formula_seen_stack &,bool) const297 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
298 {
299 return to_string_impl(true);
300 }
301
get_type() const302 virtual const VARIANT_TYPE& get_type() const override
303 {
304 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_DECIMAL;
305 return type;
306 }
307
308 private:
309 std::string to_string_impl(const bool sign_value) const;
310 };
311
312
313 class variant_callable : public variant_value_base, private callable_die_subscriber
314 {
315 public:
316 explicit variant_callable(const_formula_callable_ptr callable);
317 ~variant_callable();
318
as_bool() const319 virtual bool as_bool() const override
320 {
321 return callable_ != nullptr;
322 }
323
num_elements() const324 virtual size_t num_elements() const override
325 {
326 return 1;
327 }
328
get_callable() const329 const_formula_callable_ptr get_callable() const
330 {
331 return callable_;
332 }
333
string_cast() const334 virtual std::string string_cast() const override
335 {
336 return "(object)";
337 }
338
339 virtual std::string get_serialized_string() const override;
340
341 virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
342
343 virtual bool equals(variant_value_base& other) const override;
344 virtual bool less_than(variant_value_base& other) const override;
345
get_type() const346 virtual const VARIANT_TYPE& get_type() const override
347 {
348 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_CALLABLE;
349 return type;
350 }
351
352 virtual boost::iterator_range<variant_iterator> make_iterator() const override;
353 virtual variant deref_iterator(const boost::any& iter) const override;
354
355 virtual void iterator_inc(boost::any& iter) const override;
356 virtual void iterator_dec(boost::any& iter) const override;
iterator_equals(const boost::any &,const boost::any &) const357 virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const override
358 {
359 return true; // TODO: implement
360 }
361
362 private:
notify_dead()363 void notify_dead() override {callable_.reset();}
364
365 mutable formula_input_vector inputs; // for iteration
366 const_formula_callable_ptr callable_;
367 };
368
369
370 class variant_string : public variant_value_base
371 {
372 public:
variant_string(const std::string & str)373 explicit variant_string(const std::string& str) : string_(str) {}
374
is_empty() const375 virtual bool is_empty() const override
376 {
377 return string_.empty();
378 }
379
as_bool() const380 virtual bool as_bool() const override
381 {
382 return !is_empty();
383 }
384
get_string() const385 const std::string& get_string() const
386 {
387 return string_;
388 }
389
string_cast() const390 virtual std::string string_cast() const override
391 {
392 return string_;
393 }
394
395 virtual std::string get_serialized_string() const override;
396
get_debug_string(formula_seen_stack &,bool) const397 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
398 {
399 return string_;
400 }
401
equals(variant_value_base & other) const402 virtual bool equals(variant_value_base& other) const override
403 {
404 return string_ == value_ref_cast<variant_string>(other).string_;
405 }
406
less_than(variant_value_base & other) const407 virtual bool less_than(variant_value_base& other) const override
408 {
409 return string_ < value_ref_cast<variant_string>(other).string_;
410 }
411
get_type() const412 virtual const VARIANT_TYPE& get_type() const override
413 {
414 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_STRING;
415 return type;
416 }
417
418 private:
419 std::string string_;
420 };
421
422 /**
423 * Generalized implementation handling container variants.
424 *
425 * This class shouldn't usually be used directly. Instead, it's better to
426 * create a new derived class specialized to a specific container type.
427 */
428 template<typename T>
429 class variant_container : public variant_value_base
430 {
431 public:
variant_container(const T & container)432 explicit variant_container(const T& container)
433 : container_(container)
434 {
435 // NOTE: add more conditions if this changes.
436 static_assert((std::is_same<variant_vector, T>::value || std::is_same<variant_map_raw, T>::value),
437 "variant_container only accepts vector or map specifications.");
438 }
439
is_empty() const440 virtual bool is_empty() const override
441 {
442 return container_.empty();
443 }
444
num_elements() const445 virtual size_t num_elements() const override
446 {
447 return container_.size();
448 }
449
as_bool() const450 virtual bool as_bool() const override
451 {
452 return !is_empty();
453 }
454
get_container()455 T& get_container()
456 {
457 return container_;
458 }
459
get_container() const460 const T& get_container() const
461 {
462 return container_;
463 }
464
465 virtual std::string string_cast() const override;
466
467 virtual std::string get_serialized_string() const override;
468
469 virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
470
contains(const variant & member) const471 bool contains(const variant& member) const
472 {
473 return utils::contains<T, variant>(container_, member);
474 }
475
476 // We implement these here since the interface is the same for all
477 // specializations and leave the deref function to the derived classes.
478 virtual boost::iterator_range<variant_iterator> make_iterator() const override;
479
480 virtual void iterator_inc(boost::any&) const override;
481 virtual void iterator_dec(boost::any&) const override;
482 virtual bool iterator_equals(const boost::any& first, const boost::any& second) const override;
483
484 protected:
485 using mod_func_t = std::function<std::string(const variant&)>;
486
487 virtual std::string to_string_detail(const typename T::value_type& value, mod_func_t mod_func) const = 0;
488
489 private:
490 /**
491 * Implementation to handle string conversion for @ref string_cast, @ref get_serialized_string,
492 * and @ref get_debug_string.
493 *
494 * Derived classes should provide type-specific value handling by implementing @ref to_string_detail.
495 */
496 std::string to_string_impl(bool annotate, bool annotate_empty, mod_func_t mod_func) const;
497
498 T container_;
499 };
500
501
502 class variant_list : public variant_container<variant_vector>
503 {
504 public:
variant_list(const variant_vector & vec)505 explicit variant_list(const variant_vector& vec)
506 : variant_container<variant_vector>(vec)
507 {}
508
509 /**
510 * Applies the provided function to the corresponding variants in this and another list.
511 */
512 variant list_op(value_base_ptr second, std::function<variant(variant&, variant&)> op_func);
513
514 virtual bool equals(variant_value_base& other) const override;
515 virtual bool less_than(variant_value_base& other) const override;
516
get_type() const517 virtual const VARIANT_TYPE& get_type() const override
518 {
519 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_LIST;
520 return type;
521 }
522
523 virtual variant deref_iterator(const boost::any&) const override;
524
525 private:
to_string_detail(const variant_vector::value_type & container_val,mod_func_t mod_func) const526 virtual std::string to_string_detail(const variant_vector::value_type& container_val, mod_func_t mod_func) const override
527 {
528 return mod_func(container_val);
529 }
530 };
531
532
533 class variant_map : public variant_container<variant_map_raw>
534 {
535 public:
variant_map(const variant_map_raw & map)536 explicit variant_map(const variant_map_raw& map)
537 : variant_container<variant_map_raw>(map)
538 {}
539
540 virtual bool equals(variant_value_base& other) const override;
541 virtual bool less_than(variant_value_base& other) const override;
542
get_type() const543 virtual const VARIANT_TYPE& get_type() const override
544 {
545 static VARIANT_TYPE type = VARIANT_TYPE::TYPE_MAP;
546 return type;
547 }
548
549 virtual variant deref_iterator(const boost::any&) const override;
550
551 private:
552 virtual std::string to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const override;
553 };
554
555 } // namespace wfl
556