The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
variant.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include <cassert>
16 #include <cmath>
17 #include <iostream>
18 #include <cstring>
19 #include <stack>
20 
21 #include "formatter.hpp"
22 #include "formula/function.hpp"
23 #include "utils/math.hpp"
24 #include "log.hpp"
25 
26 static lg::log_domain log_scripting_formula("scripting/formula");
27 #define DBG_SF LOG_STREAM(debug, log_scripting_formula)
28 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
29 #define WRN_SF LOG_STREAM(warn, log_scripting_formula)
30 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
31 
32 #include <cassert>
33 #include <cmath>
34 #include <memory>
35 
36 namespace wfl
37 {
38 
39 // Static value to initialize null variants to ensure its value is never nullptr.
40 static value_base_ptr null_value(new variant_value_base);
41 
43 {
44  return VARIANT_TYPE::enum_to_string(type);
45 }
46 
47 // Small helper function to get a standard type error message.
48 static std::string was_expecting(const std::string& message, const variant& v)
49 {
50  std::ostringstream ss;
51 
52  ss << "TYPE ERROR: expected " << message << " but found "
53  << v.type_string() << " (" << v.to_debug_string() << ")";
54 
55  return ss.str();
56 }
57 
59 {
60  std::cerr << "ERROR: " << message << "\n" << call_stack_manager::get();
61 }
62 
64  : type_(VARIANT_TYPE::TYPE_NULL)
65  , container_(nullptr)
66  , iter_()
67 {
68 }
69 
70 variant_iterator::variant_iterator(const variant_value_base* value, const boost::any& iter)
71  : type_(value->get_type())
72  , container_(value)
73  , iter_(iter)
74 {
75 }
76 
78 {
79  if(!container_) {
80  return variant();
81  }
82 
84 }
85 
87 {
88  if(container_) {
90  }
91 
92  return *this;
93 }
94 
96 {
97  variant_iterator temp(*this);
98  if(container_) {
100  }
101 
102  return temp;
103 }
104 
106 {
107  if(container_) {
109  }
110 
111  return *this;
112 }
113 
115 {
116  variant_iterator temp(*this);
117  if(container_) {
119  }
120 
121  return temp;
122 }
123 
125 {
126  if(!container_ && !that.container_) {
127  return true;
128  }
129 
130  if(container_ == that.container_) {
131  return container_->iterator_equals(iter_, that.iter_);
132  }
133 
134  return false;
135 }
136 
138 {
139  return !operator==(that);
140 }
141 
142 
144  : value_(null_value)
145 {}
146 
148  : value_(std::make_shared<variant_int>(n))
149 {
150  assert(value_.get());
151 }
152 
154  : value_(std::make_shared<variant_decimal>(n))
155 {
156  assert(value_.get());
157 }
158 
160  : value_(std::make_shared<variant_decimal>(n))
161 {
162  assert(value_.get());
163 }
164 
165 variant::variant(const std::vector<variant>& vec)
166  : value_((std::make_shared<variant_list>(vec)))
167 {
168  assert(value_.get());
169 }
170 
172  : value_(std::make_shared<variant_string>(str))
173 {
174  assert(value_.get());
175 }
176 
177 variant::variant(const std::map<variant,variant>& map)
178  : value_((std::make_shared<variant_map>(map)))
179 {
180  assert(value_.get());
181 }
182 
184 {
185  value_ = v.value_;
186  return *this;
187 }
188 
190 {
191  if(is_callable()) {
192  return *this;
193  }
194 
195  must_be(VARIANT_TYPE::TYPE_LIST);
196 
197  try {
198  return value_cast<variant_list>()->get_container()[n];
199  } catch(std::out_of_range&) {
200  throw type_error("invalid index");
201  }
202 }
203 
205 {
206  if(is_callable()) {
207  return *this;
208  }
209 
210  if(is_map()) {
211  auto& map = value_cast<variant_map>()->get_container();
212 
213  auto i = map.find(v);
214  if(i == map.end()) {
215  return variant();
216  }
217 
218  return i->second;
219  } else if(is_list()) {
220  if(v.is_list()) {
221  std::vector<variant> slice;
222  for(size_t i = 0; i < v.num_elements(); ++i) {
223  slice.push_back((*this)[v[i]]);
224  }
225 
226  return variant(slice);
227  } else if(v.as_int() < 0) {
228  return operator[](num_elements() + v.as_int());
229  }
230 
231  return operator[](v.as_int());
232  }
233 
234  throw type_error(was_expecting("a list or a map", *this));
235 }
236 
238 {
239  must_be(VARIANT_TYPE::TYPE_MAP);
240 
241  std::vector<variant> tmp;
242  for(const auto& i : value_cast<variant_map>()->get_container()) {
243  tmp.push_back(i.first);
244  }
245 
246  return variant(tmp);
247 }
248 
250 {
251  must_be(VARIANT_TYPE::TYPE_MAP);
252 
253  std::vector<variant> tmp;
254  for(const auto& i : value_cast<variant_map>()->get_container()) {
255  tmp.push_back(i.second);
256  }
257 
258  return variant(tmp);
259 }
260 
262 {
263  return value_->make_iterator().begin();
264 }
265 
267 {
268  return value_->make_iterator().end();
269 }
270 
271 bool variant::is_empty() const
272 {
273  return value_->is_empty();
274 }
275 
276 size_t variant::num_elements() const
277 {
278  if(!is_list() && !is_map()) {
279  throw type_error(was_expecting("a list or a map", *this));
280  }
281 
282  return value_->num_elements();
283 }
284 
286 {
287  if(is_callable()) {
288  return value_cast<variant_callable>()->get_callable()->query_value(name);
289  }
290 
291  if(name == "self") {
292  return *this;
293  }
294 
295  return variant();
296 }
297 
298 int variant::as_int() const
299 {
300  if(is_null()) { return 0; }
301  if(is_decimal()) { return as_decimal() / 1000; }
302 
303  must_be(VARIANT_TYPE::TYPE_INT);
304  return value_cast<variant_int>()->get_numeric_value();
305 }
306 
308 {
309  if(is_decimal()) {
310  return value_cast<variant_decimal>()->get_numeric_value();
311  } else if(is_int()) {
312  return value_cast<variant_int>()->get_numeric_value() * 1000;
313  } else if(is_null()) {
314  return 0;
315  }
316 
317  throw type_error(was_expecting("an integer or a decimal", *this));
318 }
319 
320 bool variant::as_bool() const
321 {
322  return value_->as_bool();
323 }
324 
326 {
327  must_be(VARIANT_TYPE::TYPE_STRING);
328  return value_cast<variant_string>()->get_string();
329 }
330 
331 const std::vector<variant>& variant::as_list() const
332 {
333  must_be(VARIANT_TYPE::TYPE_LIST);
334  return value_cast<variant_list>()->get_container();
335 }
336 
337 const std::map<variant, variant>& variant::as_map() const
338 {
339  must_be(VARIANT_TYPE::TYPE_MAP);
340  return value_cast<variant_map>()->get_container();
341 }
342 
344 {
345  if(is_list() && v.is_list()) {
346  auto& list = value_cast<variant_list>()->get_container();
347  auto& other_list = v.value_cast<variant_list>()->get_container();
348 
349  std::vector<variant> res;
350  res.reserve(list.size() + other_list.size());
351 
352  for(const auto& member : list) {
353  res.push_back(member);
354  }
355 
356  for(const auto& member : other_list) {
357  res.push_back(member);
358  }
359 
360  return variant(res);
361  }
362 
363  if(is_map() && v.is_map()) {
364  std::map<variant, variant> res = value_cast<variant_map>()->get_container();
365 
366  for(const auto& member : v.value_cast<variant_map>()->get_container()) {
367  res[member.first] = member.second;
368  }
369 
370  return variant(res);
371  }
372 
373  if(is_decimal() || v.is_decimal()) {
374  return variant(as_decimal() + v.as_decimal() , DECIMAL_VARIANT);
375  }
376 
377  return variant(as_int() + v.as_int());
378 }
379 
381 {
382  if(is_decimal() || v.is_decimal()) {
383  return variant(as_decimal() - v.as_decimal() , DECIMAL_VARIANT);
384  }
385 
386  return variant(as_int() - v.as_int());
387 }
388 
390 {
391  if(is_decimal() || v.is_decimal()) {
392 
393  long long long_int = as_decimal();
394 
395  long_int *= v.as_decimal();
396 
397  long_int /= 100;
398 
399  if(long_int%10 >= 5) {
400  long_int /= 10;
401  ++long_int;
402  } else {
403  long_int/=10;
404  }
405 
406  return variant(static_cast<int>(long_int) , DECIMAL_VARIANT );
407  }
408 
409  return variant(as_int() * v.as_int());
410 }
411 
413 {
414  if(is_decimal() || v.is_decimal()) {
415  int denominator = v.as_decimal();
416 
417  if(denominator == 0) {
418  throw type_error("divide by zero error");
419  }
420 
421  long long long_int = as_decimal();
422 
423  long_int *= 10000;
424 
425  long_int /= denominator;
426 
427  if(long_int%10 >= 5) {
428  long_int /= 10;
429  ++long_int;
430  } else {
431  long_int/=10;
432  }
433 
434  return variant(static_cast<int>(long_int), DECIMAL_VARIANT);
435  }
436 
437  const int numerator = as_int();
438  const int denominator = v.as_int();
439 
440  if(denominator == 0) {
441  throw type_error("divide by zero error");
442  }
443 
444  return variant(numerator / denominator);
445 }
446 
448 {
449  if(is_decimal() || v.is_decimal()) {
450  const int numerator = as_decimal();
451  const int denominator = v.as_decimal();
452  if(denominator == 0) {
453  throw type_error("divide by zero error");
454  }
455 
456  return variant(numerator % denominator, DECIMAL_VARIANT);
457  } else {
458  const int numerator = as_int();
459  const int denominator = v.as_int();
460  if(denominator == 0) {
461  throw type_error("divide by zero error");
462  }
463 
464  return variant(numerator % denominator);
465  }
466 }
467 
469 {
470  if(is_decimal() || v.is_decimal()) {
471 
472  double res = pow(as_decimal() / 1000.0 , v.as_decimal() / 1000.0);
473 
474  if(std::isnan(res)) {
475  return variant();
476  }
477 
478  return variant(res, DECIMAL_VARIANT);
479  }
480 
481  return variant(static_cast<int>(round_portable(pow(static_cast<double>(as_int()), v.as_int()))));
482 }
483 
485 {
486  if(is_decimal()) {
487  return variant(-as_decimal(), DECIMAL_VARIANT);
488  }
489 
490  return variant(-as_int());
491 }
492 
493 bool variant::operator==(const variant& v) const
494 {
495  if(type() != v.type()) {
496  if(is_decimal() || v.is_decimal()) {
497  return as_decimal() == v.as_decimal();
498  }
499 
500  return false;
501  }
502 
503  return value_->equals(*v.value_);
504 }
505 
506 bool variant::operator!=(const variant& v) const
507 {
508  return !operator==(v);
509 }
510 
511 bool variant::operator<(const variant& v) const
512 {
513  if(type() != v.type()) {
514  if(is_decimal() && v.is_int()) {
515  return as_decimal() < v.as_decimal();
516  }
517 
518  if(v.is_decimal() && is_int()) {
519  return as_decimal() < v.as_decimal();
520  }
521 
522  return type() < v.type();
523  }
524 
525  return value_->less_than(*v.value_);
526 }
527 
528 bool variant::operator>=(const variant& v) const
529 {
530  return !(*this < v);
531 }
532 
533 bool variant::operator<=(const variant& v) const
534 {
535  return !(v < *this);
536 }
537 
538 bool variant::operator>(const variant& v) const
539 {
540  return v < *this;
541 }
542 
544 {
545  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
546  return value_cast<variant_list>()->list_op(v.value_, std::plus<variant>());
547 }
548 
550 {
551  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
552  return value_cast<variant_list>()->list_op(v.value_, std::minus<variant>());
553 }
554 
556 {
557  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
558  return value_cast<variant_list>()->list_op(v.value_, std::multiplies<variant>());
559 }
560 
562 {
563  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
564  return value_cast<variant_list>()->list_op(v.value_, std::divides<variant>());
565 }
566 
568 {
569  if(is_list()) {
570  v.must_be(VARIANT_TYPE::TYPE_LIST);
571 
572  std::vector<variant> res;
573  res.reserve(num_elements() + v.num_elements());
574 
575  for(size_t i = 0; i < num_elements(); ++i) {
576  res.push_back((*this)[i]);
577  }
578 
579  for(size_t i = 0; i < v.num_elements(); ++i) {
580  res.push_back(v[i]);
581  }
582 
583  return variant(res);
584  } else if(is_string()) {
585  v.must_be(VARIANT_TYPE::TYPE_STRING);
586  std::string res = as_string() + v.as_string();
587  return variant(res);
588  }
589 
590  throw type_error(was_expecting("a list or a string", *this));
591 }
592 
594 {
595  must_both_be(VARIANT_TYPE::TYPE_INT, v);
596 
597  return value_cast<variant_int>()->build_range_variant(v.as_int());
598 }
599 
600 bool variant::contains(const variant& v) const
601 {
602  if(!is_list() && !is_map()) {
603  throw type_error(was_expecting("a list or a map", *this));
604  }
605 
606  if(is_list()) {
607  return value_cast<variant_list>()->contains(v);
608  } else {
609  return value_cast<variant_map>()->contains(v);
610  }
611 }
612 
613 void variant::must_be(VARIANT_TYPE t) const
614 {
615  if(type() != t) {
617  }
618 }
619 
620 void variant::must_both_be(VARIANT_TYPE t, const variant& second) const
621 {
622  if(type() != t || second.type() != t) {
623  throw type_error(formatter() << "TYPE ERROR: expected two "
624  << variant_type_to_string(t) << " but found "
625  << type_string() << " (" << to_debug_string() << ")" << " and "
626  << second.type_string() << " (" << second.to_debug_string() << ")");
627  }
628 }
629 
631 {
632  return value_->get_serialized_string();
633 }
634 
636 {
637  try {
638  *this = formula(str).evaluate();
639  } catch(...) {
640  *this = variant(str);
641  }
642 }
643 
645 {
646  return value_->string_cast();
647 }
648 
650 {
651  if(!seen) {
652  formula_seen_stack seen_stack;
653  return value_->get_debug_string(seen_stack, verbose);
654  }
655 
656  return value_->get_debug_string(*seen, verbose);
657 }
658 
660 {
661  std::stack<variant> vars;
662  if(var.is_list()) {
663  for(size_t n = 1; n <= var.num_elements(); ++n) {
664  vars.push(var[var.num_elements() - n]);
665  }
666  } else {
667  vars.push(var);
668  }
669 
670  std::vector<variant> made_moves;
671 
672  while(!vars.empty()) {
673 
674  if(vars.top().is_null()) {
675  vars.pop();
676  continue;
677  }
678 
679  if(auto action = vars.top().try_convert<action_callable>()) {
680  variant res = action->execute_self(*this);
681  if(res.is_int() && res.as_bool()) {
682  made_moves.push_back(vars.top());
683  }
684  } else if(vars.top().is_string() && vars.top().as_string() == "continue") {
685 // if(infinite_loop_guardian_.continue_check()) {
686  made_moves.push_back(vars.top());
687 // } else {
688  //too many calls in a row - possible infinite loop
689 // ERR_SF << "ERROR #5001 while executing 'continue' formula keyword" << std::endl;
690 
691 // if(safe_call)
692 // error = variant(new game_logic::safe_call_result(nullptr, 5001));
693 // }
694  } else if(vars.top().is_string() && (vars.top().as_string() == "end_turn" || vars.top().as_string() == "end")) {
695  break;
696  } else {
697  //this information is unneeded when evaluating formulas from commandline
698  ERR_SF << "UNRECOGNIZED MOVE: " << vars.top().to_debug_string() << std::endl;
699  }
700 
701  vars.pop();
702  }
703 
704  return variant(made_moves);
705 }
706 
707 }
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:659
bool is_int() const
Definition: variant.hpp:59
virtual void iterator_dec(boost::any &) const
Implements the decrement functionality of variant_iterator for a value of this type.
std::vector< char_t > string
void must_be(VARIANT_TYPE t) const
Definition: variant.cpp:613
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:39
bool operator<=(const variant &) const
Definition: variant.cpp:533
variant operator%(const variant &) const
Definition: variant.cpp:447
std::shared_ptr< variant_value_base > value_base_ptr
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
DECIMAL_VARIANT_TYPE
Definition: variant.hpp:30
bool operator>=(const variant &) const
Definition: variant.cpp:528
value_base_ptr value_
Variant value.
Definition: variant.hpp:171
int as_int() const
Definition: variant.cpp:298
variant list_elements_div(const variant &v) const
Definition: variant.cpp:561
variant & operator=(const variant &v)
Definition: variant.cpp:183
std::shared_ptr< T > value_cast() const
Definition: variant.hpp:153
bool operator!=(const variant &) const
Definition: variant.cpp:506
const std::vector< variant > & as_list() const
Definition: variant.cpp:331
STL namespace.
static std::string was_expecting(const std::string &message, const variant &v)
Definition: variant.cpp:48
variant_iterator end() const
Definition: variant.cpp:266
virtual variant deref_iterator(const boost::any &iter) const
Implements the dereference functionality of variant_iterator for a value of this type.
bool operator==(const variant_iterator &that) const
Definition: variant.cpp:124
variant_iterator & operator++()
Definition: variant.cpp:86
#define ERR_SF
Definition: variant.cpp:30
variant get_member(const std::string &name) const
Definition: variant.cpp:285
virtual void iterator_inc(boost::any &) const
Implements the increment functionality of variant_iterator for a value of this type.
static lg::log_domain log_scripting_formula("scripting/formula")
VARIANT_TYPE type() const
Definition: variant.hpp:162
bool contains(const variant &other) const
Definition: variant.cpp:600
std::ostringstream wrapper.
Definition: formatter.hpp:38
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:320
static std::string get()
Definition: function.cpp:51
bool is_callable() const
Definition: variant.hpp:61
General math utility functions.
variant_iterator & operator--()
Definition: variant.cpp:105
void serialize_from_string(const std::string &str)
Definition: variant.cpp:635
variant list_elements_sub(const variant &v) const
Definition: variant.cpp:549
type_error(const std::string &str)
Definition: variant.cpp:58
variant operator^(const variant &) const
Definition: variant.cpp:468
static value_base_ptr null_value(new variant_value_base)
variant operator[](size_t n) const
Definition: variant.cpp:189
variant operator+(const variant &) const
Definition: variant.cpp:343
bool operator>(const variant &) const
Definition: variant.cpp:538
std::string string_cast() const
Definition: variant.cpp:644
bool is_empty() const
Definition: variant.cpp:271
variant operator*() const
Definition: variant.cpp:77
int as_decimal() const
Returns variant's internal representation of decimal number: ie, 1.234 is represented as 1234...
Definition: variant.cpp:307
const std::map< variant, variant > & as_map() const
Definition: variant.cpp:337
variant get_keys() const
Definition: variant.cpp:237
variant build_range(const variant &v) const
Definition: variant.cpp:593
std::vector< const_formula_callable_ptr > formula_seen_stack
size_t i
Definition: function.cpp:933
const variant_value_base * container_
Definition: variant.hpp:215
bool is_list() const
Definition: variant.hpp:62
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:58
virtual bool iterator_equals(const boost::any &, const boost::any &) const
Implements the equality functionality of variant_iterator for a value of this type.
variant operator/(const variant &) const
Definition: variant.cpp:412
void must_both_be(VARIANT_TYPE t, const variant &second) const
Definition: variant.cpp:620
bool operator==(const variant &) const
Definition: variant.cpp:493
std::string type_string() const
Gets string name of the current value type.
Definition: variant.hpp:144
bool is_map() const
Definition: variant.hpp:64
double t
Definition: astarsearch.cpp:64
Definition: contexts.hpp:42
variant operator*(const variant &) const
Definition: variant.cpp:389
size_t num_elements() const
Definition: variant.cpp:276
Standard logging facilities (interface).
bool is_string() const
Definition: variant.hpp:63
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:649
std::string message
Definition: exceptions.hpp:31
bool is_decimal() const
Definition: variant.hpp:60
variant concatenate(const variant &v) const
Definition: variant.cpp:567
Base class for all variant types.
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
variant_iterator begin() const
Definition: variant.cpp:261
variant_iterator()
Constructor for a no-op iterator.
Definition: variant.cpp:63
bool operator!=(const variant_iterator &that) const
Definition: variant.cpp:137
const std::string & as_string() const
Definition: variant.cpp:325
std::string serialize_to_string() const
Definition: variant.cpp:630
static std::string variant_type_to_string(VARIANT_TYPE type)
Definition: variant.cpp:42
variant list_elements_mul(const variant &v) const
Definition: variant.cpp:555
Iterator class for the variant.
Definition: variant.hpp:182
variant get_values() const
Definition: variant.cpp:249
static map_location::DIRECTION n
variant list_elements_add(const variant &v) const
Definition: variant.cpp:543
variant operator-() const
Definition: variant.cpp:484
double round_portable(double d)
Definition: math.hpp:74
bool operator<(const variant &) const
Definition: variant.cpp:511