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