The Battle for Wesnoth  1.15.12+dev
variant.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://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 
42 static std::string variant_type_to_string(VARIANT_TYPE type)
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 
58 type_error::type_error(const std::string& str) : game::error(str)
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 
171 variant::variant(const std::string& str)
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 
183 variant variant::operator[](std::size_t n) const
184 {
185  if(is_callable()) {
186  return *this;
187  }
188 
189  must_be(VARIANT_TYPE::TYPE_LIST);
190 
191  try {
192  return value_cast<variant_list>()->get_container().at(n);
193  } catch(std::out_of_range&) {
194  throw type_error("invalid index");
195  }
196 }
197 
199 {
200  if(is_callable()) {
201  return *this;
202  }
203 
204  if(is_map()) {
205  auto& map = value_cast<variant_map>()->get_container();
206 
207  auto i = map.find(v);
208  if(i == map.end()) {
209  return variant();
210  }
211 
212  return i->second;
213  } else if(is_list()) {
214  if(v.is_list()) {
215  std::vector<variant> slice;
216  for(std::size_t i = 0; i < v.num_elements(); ++i) {
217  slice.push_back((*this)[v[i]]);
218  }
219 
220  return variant(slice);
221  } else if(v.as_int() < 0) {
222  return operator[](num_elements() + v.as_int());
223  }
224 
225  return operator[](v.as_int());
226  }
227 
228  throw type_error(was_expecting("a list or a map", *this));
229 }
230 
232 {
233  must_be(VARIANT_TYPE::TYPE_MAP);
234 
235  std::vector<variant> tmp;
236  for(const auto& i : value_cast<variant_map>()->get_container()) {
237  tmp.push_back(i.first);
238  }
239 
240  return variant(tmp);
241 }
242 
244 {
245  must_be(VARIANT_TYPE::TYPE_MAP);
246 
247  std::vector<variant> tmp;
248  for(const auto& i : value_cast<variant_map>()->get_container()) {
249  tmp.push_back(i.second);
250  }
251 
252  return variant(tmp);
253 }
254 
256 {
257  return value_->make_iterator().begin();
258 }
259 
261 {
262  return value_->make_iterator().end();
263 }
264 
265 bool variant::is_empty() const
266 {
267  return value_->is_empty();
268 }
269 
270 std::size_t variant::num_elements() const
271 {
272  if(!is_list() && !is_map()) {
273  throw type_error(was_expecting("a list or a map", *this));
274  }
275 
276  return value_->num_elements();
277 }
278 
279 variant variant::get_member(const std::string& name) const
280 {
281  if(is_callable()) {
282  if(auto obj = value_cast<variant_callable>()->get_callable()) {
283  return obj->query_value(name);
284  }
285  }
286 
287  if(name == "self") {
288  return *this;
289  }
290 
291  return variant();
292 }
293 
294 int variant::as_int() const
295 {
296  if(is_null()) { return 0; }
297  if(is_decimal()) { return as_decimal() / 1000; }
298 
299  must_be(VARIANT_TYPE::TYPE_INT);
300  return value_cast<variant_int>()->get_numeric_value();
301 }
302 
304 {
305  if(is_decimal()) {
306  return value_cast<variant_decimal>()->get_numeric_value();
307  } else if(is_int()) {
308  return value_cast<variant_int>()->get_numeric_value() * 1000;
309  } else if(is_null()) {
310  return 0;
311  }
312 
313  throw type_error(was_expecting("an integer or a decimal", *this));
314 }
315 
316 bool variant::as_bool() const
317 {
318  return value_->as_bool();
319 }
320 
321 const std::string& variant::as_string() const
322 {
323  must_be(VARIANT_TYPE::TYPE_STRING);
324  return value_cast<variant_string>()->get_string();
325 }
326 
327 const std::vector<variant>& variant::as_list() const
328 {
329  must_be(VARIANT_TYPE::TYPE_LIST);
330  return value_cast<variant_list>()->get_container();
331 }
332 
333 const std::map<variant, variant>& variant::as_map() const
334 {
335  must_be(VARIANT_TYPE::TYPE_MAP);
336  return value_cast<variant_map>()->get_container();
337 }
338 
340 {
341  if(is_list() && v.is_list()) {
342  auto& list = value_cast<variant_list>()->get_container();
343  auto& other_list = v.value_cast<variant_list>()->get_container();
344 
345  std::vector<variant> res;
346  res.reserve(list.size() + other_list.size());
347 
348  for(const auto& member : list) {
349  res.push_back(member);
350  }
351 
352  for(const auto& member : other_list) {
353  res.push_back(member);
354  }
355 
356  return variant(res);
357  }
358 
359  if(is_map() && v.is_map()) {
360  std::map<variant, variant> res = value_cast<variant_map>()->get_container();
361 
362  for(const auto& member : v.value_cast<variant_map>()->get_container()) {
363  res[member.first] = member.second;
364  }
365 
366  return variant(res);
367  }
368 
369  if(is_decimal() || v.is_decimal()) {
370  return variant(as_decimal() + v.as_decimal() , DECIMAL_VARIANT);
371  }
372 
373  return variant(as_int() + v.as_int());
374 }
375 
377 {
378  if(is_decimal() || v.is_decimal()) {
379  return variant(as_decimal() - v.as_decimal() , DECIMAL_VARIANT);
380  }
381 
382  return variant(as_int() - v.as_int());
383 }
384 
386 {
387  if(is_decimal() || v.is_decimal()) {
388 
389  long long long_int = as_decimal();
390 
391  long_int *= v.as_decimal();
392 
393  long_int /= 100;
394 
395  if(long_int%10 >= 5) {
396  long_int /= 10;
397  ++long_int;
398  } else {
399  long_int/=10;
400  }
401 
402  return variant(static_cast<int>(long_int) , DECIMAL_VARIANT );
403  }
404 
405  return variant(as_int() * v.as_int());
406 }
407 
409 {
410  if(is_decimal() || v.is_decimal()) {
411  int denominator = v.as_decimal();
412 
413  if(denominator == 0) {
414  throw type_error("decimal divide by zero error");
415  }
416 
417  long long long_int = as_decimal();
418 
419  long_int *= 10000;
420 
421  long_int /= denominator;
422 
423  if(long_int%10 >= 5) {
424  long_int /= 10;
425  ++long_int;
426  } else {
427  long_int/=10;
428  }
429 
430  return variant(static_cast<int>(long_int), DECIMAL_VARIANT);
431  }
432 
433  const int numerator = as_int();
434  const int denominator = v.as_int();
435 
436  if(denominator == 0) {
437  throw type_error("int divide by zero error");
438  }
439 
440  return variant(numerator / denominator);
441 }
442 
444 {
445  if(is_decimal() || v.is_decimal()) {
446  const int numerator = as_decimal();
447  const int denominator = v.as_decimal();
448  if(denominator == 0) {
449  throw type_error("divide by zero error");
450  }
451 
452  return variant(numerator % denominator, DECIMAL_VARIANT);
453  } else {
454  const int numerator = as_int();
455  const int denominator = v.as_int();
456  if(denominator == 0) {
457  throw type_error("divide by zero error");
458  }
459 
460  return variant(numerator % denominator);
461  }
462 }
463 
465 {
466  if(is_decimal() || v.is_decimal()) {
467 
468  double res = std::pow(as_decimal() / 1000.0 , v.as_decimal() / 1000.0);
469 
470  if(std::isnan(res)) {
471  return variant();
472  }
473 
474  return variant(res, DECIMAL_VARIANT);
475  }
476 
477  return variant(static_cast<int>(std::round(std::pow(static_cast<double>(as_int()), v.as_int()))));
478 }
479 
481 {
482  if(is_decimal()) {
483  return variant(-as_decimal(), DECIMAL_VARIANT);
484  }
485 
486  return variant(-as_int());
487 }
488 
489 bool variant::operator==(const variant& v) const
490 {
491  if(type() != v.type()) {
492  if(is_decimal() || v.is_decimal()) {
493  return as_decimal() == v.as_decimal();
494  }
495 
496  return false;
497  }
498 
499  return value_->equals(*v.value_);
500 }
501 
502 bool variant::operator!=(const variant& v) const
503 {
504  return !operator==(v);
505 }
506 
507 bool variant::operator<(const variant& v) const
508 {
509  if(type() != v.type()) {
510  if(is_decimal() && v.is_int()) {
511  return as_decimal() < v.as_decimal();
512  }
513 
514  if(v.is_decimal() && is_int()) {
515  return as_decimal() < v.as_decimal();
516  }
517 
518  return type() < v.type();
519  }
520 
521  return value_->less_than(*v.value_);
522 }
523 
524 bool variant::operator>=(const variant& v) const
525 {
526  return !(*this < v);
527 }
528 
529 bool variant::operator<=(const variant& v) const
530 {
531  return !(v < *this);
532 }
533 
534 bool variant::operator>(const variant& v) const
535 {
536  return v < *this;
537 }
538 
540 {
541  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
542  return value_cast<variant_list>()->list_op(v.value_, std::plus<variant>());
543 }
544 
546 {
547  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
548  return value_cast<variant_list>()->list_op(v.value_, std::minus<variant>());
549 }
550 
552 {
553  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
554  return value_cast<variant_list>()->list_op(v.value_, std::multiplies<variant>());
555 }
556 
558 {
559  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
560  return value_cast<variant_list>()->list_op(v.value_, std::divides<variant>());
561 }
562 
564 {
565  if(is_list()) {
566  v.must_be(VARIANT_TYPE::TYPE_LIST);
567 
568  std::vector<variant> res;
569  res.reserve(num_elements() + v.num_elements());
570 
571  for(std::size_t i = 0; i < num_elements(); ++i) {
572  res.push_back((*this)[i]);
573  }
574 
575  for(std::size_t i = 0; i < v.num_elements(); ++i) {
576  res.push_back(v[i]);
577  }
578 
579  return variant(res);
580  } else if(is_string()) {
581  v.must_be(VARIANT_TYPE::TYPE_STRING);
582  std::string res = as_string() + v.as_string();
583  return variant(res);
584  }
585 
586  throw type_error(was_expecting("a list or a string", *this));
587 }
588 
590 {
591  must_both_be(VARIANT_TYPE::TYPE_INT, v);
592 
593  return value_cast<variant_int>()->build_range_variant(v.as_int());
594 }
595 
596 bool variant::contains(const variant& v) const
597 {
598  if(!is_list() && !is_map()) {
599  throw type_error(was_expecting("a list or a map", *this));
600  }
601 
602  if(is_list()) {
603  return value_cast<variant_list>()->contains(v);
604  } else {
605  return value_cast<variant_map>()->contains(v);
606  }
607 }
608 
609 void variant::must_be(VARIANT_TYPE t) const
610 {
611  if(type() != t) {
613  }
614 }
615 
616 void variant::must_both_be(VARIANT_TYPE t, const variant& second) const
617 {
618  if(type() != t || second.type() != t) {
619  throw type_error(formatter() << "TYPE ERROR: expected two "
620  << variant_type_to_string(t) << " but found "
621  << type_string() << " (" << to_debug_string() << ")" << " and "
622  << second.type_string() << " (" << second.to_debug_string() << ")");
623  }
624 }
625 
626 std::string variant::serialize_to_string() const
627 {
628  return value_->get_serialized_string();
629 }
630 
631 void variant::serialize_from_string(const std::string& str)
632 {
633  try {
634  *this = formula(str).evaluate();
635  } catch(...) {
636  *this = variant(str);
637  }
638 }
639 
640 std::string variant::string_cast() const
641 {
642  return value_->string_cast();
643 }
644 
645 std::string variant::to_debug_string(bool verbose, formula_seen_stack* seen) const
646 {
647  if(!seen) {
648  formula_seen_stack seen_stack;
649  return value_->get_debug_string(seen_stack, verbose);
650  }
651 
652  return value_->get_debug_string(*seen, verbose);
653 }
654 
656 {
657  std::stack<variant> vars;
658  if(var.is_list()) {
659  for(std::size_t n = 1; n <= var.num_elements(); ++n) {
660  vars.push(var[var.num_elements() - n]);
661  }
662  } else {
663  vars.push(var);
664  }
665 
666  std::vector<variant> made_moves;
667 
668  while(!vars.empty()) {
669 
670  if(vars.top().is_null()) {
671  vars.pop();
672  continue;
673  }
674 
675  if(auto action = vars.top().try_convert<action_callable>()) {
676  variant res = action->execute_self(*this);
677  if(res.is_int() && res.as_bool()) {
678  made_moves.push_back(vars.top());
679  }
680  } else if(vars.top().is_string() && vars.top().as_string() == "continue") {
681 // if(infinite_loop_guardian_.continue_check()) {
682  made_moves.push_back(vars.top());
683 // } else {
684  //too many calls in a row - possible infinite loop
685 // ERR_SF << "ERROR #5001 while executing 'continue' formula keyword" << std::endl;
686 
687 // if(safe_call)
688 // error = variant(new game_logic::safe_call_result(nullptr, 5001));
689 // }
690  } else if(vars.top().is_string() && (vars.top().as_string() == "end_turn" || vars.top().as_string() == "end")) {
691  break;
692  } else {
693  //this information is unneeded when evaluating formulas from commandline
694  ERR_SF << "UNRECOGNIZED MOVE: " << vars.top().to_debug_string() << std::endl;
695  }
696 
697  vars.pop();
698  }
699 
700  return variant(made_moves);
701 }
702 
703 }
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:655
std::string type_string() const
Gets string name of the current value type.
Definition: variant.hpp:147
void must_both_be(VARIANT_TYPE t, const variant &second) const
Definition: variant.cpp:616
bool is_map() const
Definition: variant.hpp:67
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
variant operator*() const
Definition: variant.cpp:77
std::shared_ptr< variant_value_base > value_base_ptr
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
int as_int() const
Definition: variant.cpp:294
DECIMAL_VARIANT_TYPE
Definition: variant.hpp:30
value_base_ptr value_
Variant value.
Definition: variant.hpp:174
bool contains(const variant &other) const
Definition: variant.cpp:596
bool is_string() const
Definition: variant.hpp:66
bool is_callable() const
Definition: variant.hpp:64
variant operator-() const
Definition: variant.cpp:480
const std::map< variant, variant > & as_map() const
Definition: variant.cpp:333
STL namespace.
static std::string was_expecting(const std::string &message, const variant &v)
Definition: variant.cpp:48
variant operator%(const variant &) const
Definition: variant.cpp:443
virtual bool iterator_equals(const boost::any &, const boost::any &) const
Implements the equality functionality of variant_iterator for a value of this type.
bool is_list() const
Definition: variant.hpp:65
variant_iterator & operator++()
Definition: variant.cpp:86
#define ERR_SF
Definition: variant.cpp:30
const std::vector< variant > & as_list() const
Definition: variant.cpp:327
bool is_decimal() const
Definition: variant.hpp:63
bool is_int() const
Definition: variant.hpp:62
const std::string & as_string() const
Definition: variant.cpp:321
bool operator<=(const variant &) const
Definition: variant.cpp:529
static lg::log_domain log_scripting_formula("scripting/formula")
int as_decimal() const
Returns variant&#39;s internal representation of decimal number: ie, 1.234 is represented as 1234...
Definition: variant.cpp:303
std::ostringstream wrapper.
Definition: formatter.hpp:38
static std::string get()
Definition: function.cpp:58
std::shared_ptr< T > value_cast() const
Definition: variant.hpp:156
General math utility functions.
variant_iterator & operator--()
Definition: variant.cpp:105
void serialize_from_string(const std::string &str)
Definition: variant.cpp:631
variant list_elements_add(const variant &v) const
Definition: variant.cpp:539
VARIANT_TYPE type_
Definition: variant.hpp:217
bool operator!=(const variant &) const
Definition: variant.cpp:502
std::string serialize_to_string() const
Definition: variant.cpp:626
variant_iterator end() const
Definition: variant.cpp:260
virtual void iterator_dec(boost::any &) const
Implements the decrement functionality of variant_iterator for a value of this type.
void must_be(VARIANT_TYPE t) const
Definition: variant.cpp:609
variant list_elements_mul(const variant &v) const
Definition: variant.cpp:551
variant operator/(const variant &) const
Definition: variant.cpp:408
type_error(const std::string &str)
Definition: variant.cpp:58
bool operator==(const variant_iterator &that) const
Definition: variant.cpp:124
variant build_range(const variant &v) const
Definition: variant.cpp:589
std::string string_cast() const
Definition: variant.cpp:640
static value_base_ptr null_value(new variant_value_base)
variant list_elements_div(const variant &v) const
Definition: variant.cpp:557
VARIANT_TYPE type() const
Definition: variant.hpp:165
std::size_t i
Definition: function.cpp:940
std::vector< const_formula_callable_ptr > formula_seen_stack
bool operator>(const variant &) const
Definition: variant.cpp:534
const variant_value_base * container_
Definition: variant.hpp:218
virtual variant deref_iterator(const boost::any &iter) const
Implements the dereference functionality of variant_iterator for a value of this type.
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:61
bool operator!=(const variant_iterator &that) const
Definition: variant.cpp:137
variant concatenate(const variant &v) const
Definition: variant.cpp:563
variant operator+(const variant &) const
Definition: variant.cpp:339
double t
Definition: astarsearch.cpp:64
Definition: contexts.hpp:43
variant get_keys() const
Definition: variant.cpp:231
variant_iterator begin() const
Definition: variant.cpp:255
Standard logging facilities (interface).
variant get_values() const
Definition: variant.cpp:243
bool operator<(const variant &) const
Definition: variant.cpp:507
std::string message
Definition: exceptions.hpp:29
Base class for all variant types.
std::size_t num_elements() const
Definition: variant.cpp:270
variant_iterator()
Constructor for a no-op iterator.
Definition: variant.cpp:63
static std::string variant_type_to_string(VARIANT_TYPE type)
Definition: variant.cpp:42
variant get_member(const std::string &name) const
Definition: variant.cpp:279
Iterator class for the variant.
Definition: variant.hpp:185
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:316
virtual void iterator_inc(boost::any &) const
Implements the increment functionality of variant_iterator for a value of this type.
static map_location::DIRECTION n
bool operator>=(const variant &) const
Definition: variant.cpp:524
variant operator[](std::size_t n) const
Definition: variant.cpp:183
variant operator^(const variant &) const
Definition: variant.cpp:464
bool is_empty() const
Definition: variant.cpp:265
variant list_elements_sub(const variant &v) const
Definition: variant.cpp:545
variant operator*(const variant &) const
Definition: variant.cpp:385
bool operator==(const variant &) const
Definition: variant.cpp:489
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:645