The Battle for Wesnoth  1.15.2+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()[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  return value_cast<variant_callable>()->get_callable()->query_value(name);
283  }
284 
285  if(name == "self") {
286  return *this;
287  }
288 
289  return variant();
290 }
291 
292 int variant::as_int() const
293 {
294  if(is_null()) { return 0; }
295  if(is_decimal()) { return as_decimal() / 1000; }
296 
297  must_be(VARIANT_TYPE::TYPE_INT);
298  return value_cast<variant_int>()->get_numeric_value();
299 }
300 
302 {
303  if(is_decimal()) {
304  return value_cast<variant_decimal>()->get_numeric_value();
305  } else if(is_int()) {
306  return value_cast<variant_int>()->get_numeric_value() * 1000;
307  } else if(is_null()) {
308  return 0;
309  }
310 
311  throw type_error(was_expecting("an integer or a decimal", *this));
312 }
313 
314 bool variant::as_bool() const
315 {
316  return value_->as_bool();
317 }
318 
319 const std::string& variant::as_string() const
320 {
321  must_be(VARIANT_TYPE::TYPE_STRING);
322  return value_cast<variant_string>()->get_string();
323 }
324 
325 const std::vector<variant>& variant::as_list() const
326 {
327  must_be(VARIANT_TYPE::TYPE_LIST);
328  return value_cast<variant_list>()->get_container();
329 }
330 
331 const std::map<variant, variant>& variant::as_map() const
332 {
333  must_be(VARIANT_TYPE::TYPE_MAP);
334  return value_cast<variant_map>()->get_container();
335 }
336 
338 {
339  if(is_list() && v.is_list()) {
340  auto& list = value_cast<variant_list>()->get_container();
341  auto& other_list = v.value_cast<variant_list>()->get_container();
342 
343  std::vector<variant> res;
344  res.reserve(list.size() + other_list.size());
345 
346  for(const auto& member : list) {
347  res.push_back(member);
348  }
349 
350  for(const auto& member : other_list) {
351  res.push_back(member);
352  }
353 
354  return variant(res);
355  }
356 
357  if(is_map() && v.is_map()) {
358  std::map<variant, variant> res = value_cast<variant_map>()->get_container();
359 
360  for(const auto& member : v.value_cast<variant_map>()->get_container()) {
361  res[member.first] = member.second;
362  }
363 
364  return variant(res);
365  }
366 
367  if(is_decimal() || v.is_decimal()) {
368  return variant(as_decimal() + v.as_decimal() , DECIMAL_VARIANT);
369  }
370 
371  return variant(as_int() + v.as_int());
372 }
373 
375 {
376  if(is_decimal() || v.is_decimal()) {
377  return variant(as_decimal() - v.as_decimal() , DECIMAL_VARIANT);
378  }
379 
380  return variant(as_int() - v.as_int());
381 }
382 
384 {
385  if(is_decimal() || v.is_decimal()) {
386 
387  long long long_int = as_decimal();
388 
389  long_int *= v.as_decimal();
390 
391  long_int /= 100;
392 
393  if(long_int%10 >= 5) {
394  long_int /= 10;
395  ++long_int;
396  } else {
397  long_int/=10;
398  }
399 
400  return variant(static_cast<int>(long_int) , DECIMAL_VARIANT );
401  }
402 
403  return variant(as_int() * v.as_int());
404 }
405 
407 {
408  if(is_decimal() || v.is_decimal()) {
409  int denominator = v.as_decimal();
410 
411  if(denominator == 0) {
412  throw type_error("divide by zero error");
413  }
414 
415  long long long_int = as_decimal();
416 
417  long_int *= 10000;
418 
419  long_int /= denominator;
420 
421  if(long_int%10 >= 5) {
422  long_int /= 10;
423  ++long_int;
424  } else {
425  long_int/=10;
426  }
427 
428  return variant(static_cast<int>(long_int), DECIMAL_VARIANT);
429  }
430 
431  const int numerator = as_int();
432  const int denominator = v.as_int();
433 
434  if(denominator == 0) {
435  throw type_error("divide by zero error");
436  }
437 
438  return variant(numerator / denominator);
439 }
440 
442 {
443  if(is_decimal() || v.is_decimal()) {
444  const int numerator = as_decimal();
445  const int denominator = v.as_decimal();
446  if(denominator == 0) {
447  throw type_error("divide by zero error");
448  }
449 
450  return variant(numerator % denominator, DECIMAL_VARIANT);
451  } else {
452  const int numerator = as_int();
453  const int denominator = v.as_int();
454  if(denominator == 0) {
455  throw type_error("divide by zero error");
456  }
457 
458  return variant(numerator % denominator);
459  }
460 }
461 
463 {
464  if(is_decimal() || v.is_decimal()) {
465 
466  double res = std::pow(as_decimal() / 1000.0 , v.as_decimal() / 1000.0);
467 
468  if(std::isnan(res)) {
469  return variant();
470  }
471 
472  return variant(res, DECIMAL_VARIANT);
473  }
474 
475  return variant(static_cast<int>(std::round(std::pow(static_cast<double>(as_int()), v.as_int()))));
476 }
477 
479 {
480  if(is_decimal()) {
481  return variant(-as_decimal(), DECIMAL_VARIANT);
482  }
483 
484  return variant(-as_int());
485 }
486 
487 bool variant::operator==(const variant& v) const
488 {
489  if(type() != v.type()) {
490  if(is_decimal() || v.is_decimal()) {
491  return as_decimal() == v.as_decimal();
492  }
493 
494  return false;
495  }
496 
497  return value_->equals(*v.value_);
498 }
499 
500 bool variant::operator!=(const variant& v) const
501 {
502  return !operator==(v);
503 }
504 
505 bool variant::operator<(const variant& v) const
506 {
507  if(type() != v.type()) {
508  if(is_decimal() && v.is_int()) {
509  return as_decimal() < v.as_decimal();
510  }
511 
512  if(v.is_decimal() && is_int()) {
513  return as_decimal() < v.as_decimal();
514  }
515 
516  return type() < v.type();
517  }
518 
519  return value_->less_than(*v.value_);
520 }
521 
522 bool variant::operator>=(const variant& v) const
523 {
524  return !(*this < v);
525 }
526 
527 bool variant::operator<=(const variant& v) const
528 {
529  return !(v < *this);
530 }
531 
532 bool variant::operator>(const variant& v) const
533 {
534  return v < *this;
535 }
536 
538 {
539  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
540  return value_cast<variant_list>()->list_op(v.value_, std::plus<variant>());
541 }
542 
544 {
545  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
546  return value_cast<variant_list>()->list_op(v.value_, std::minus<variant>());
547 }
548 
550 {
551  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
552  return value_cast<variant_list>()->list_op(v.value_, std::multiplies<variant>());
553 }
554 
556 {
557  must_both_be(VARIANT_TYPE::TYPE_LIST, v);
558  return value_cast<variant_list>()->list_op(v.value_, std::divides<variant>());
559 }
560 
562 {
563  if(is_list()) {
564  v.must_be(VARIANT_TYPE::TYPE_LIST);
565 
566  std::vector<variant> res;
567  res.reserve(num_elements() + v.num_elements());
568 
569  for(std::size_t i = 0; i < num_elements(); ++i) {
570  res.push_back((*this)[i]);
571  }
572 
573  for(std::size_t i = 0; i < v.num_elements(); ++i) {
574  res.push_back(v[i]);
575  }
576 
577  return variant(res);
578  } else if(is_string()) {
579  v.must_be(VARIANT_TYPE::TYPE_STRING);
580  std::string res = as_string() + v.as_string();
581  return variant(res);
582  }
583 
584  throw type_error(was_expecting("a list or a string", *this));
585 }
586 
588 {
589  must_both_be(VARIANT_TYPE::TYPE_INT, v);
590 
591  return value_cast<variant_int>()->build_range_variant(v.as_int());
592 }
593 
594 bool variant::contains(const variant& v) const
595 {
596  if(!is_list() && !is_map()) {
597  throw type_error(was_expecting("a list or a map", *this));
598  }
599 
600  if(is_list()) {
601  return value_cast<variant_list>()->contains(v);
602  } else {
603  return value_cast<variant_map>()->contains(v);
604  }
605 }
606 
607 void variant::must_be(VARIANT_TYPE t) const
608 {
609  if(type() != t) {
611  }
612 }
613 
614 void variant::must_both_be(VARIANT_TYPE t, const variant& second) const
615 {
616  if(type() != t || second.type() != t) {
617  throw type_error(formatter() << "TYPE ERROR: expected two "
618  << variant_type_to_string(t) << " but found "
619  << type_string() << " (" << to_debug_string() << ")" << " and "
620  << second.type_string() << " (" << second.to_debug_string() << ")");
621  }
622 }
623 
624 std::string variant::serialize_to_string() const
625 {
626  return value_->get_serialized_string();
627 }
628 
629 void variant::serialize_from_string(const std::string& str)
630 {
631  try {
632  *this = formula(str).evaluate();
633  } catch(...) {
634  *this = variant(str);
635  }
636 }
637 
638 std::string variant::string_cast() const
639 {
640  return value_->string_cast();
641 }
642 
643 std::string variant::to_debug_string(bool verbose, formula_seen_stack* seen) const
644 {
645  if(!seen) {
646  formula_seen_stack seen_stack;
647  return value_->get_debug_string(seen_stack, verbose);
648  }
649 
650  return value_->get_debug_string(*seen, verbose);
651 }
652 
654 {
655  std::stack<variant> vars;
656  if(var.is_list()) {
657  for(std::size_t n = 1; n <= var.num_elements(); ++n) {
658  vars.push(var[var.num_elements() - n]);
659  }
660  } else {
661  vars.push(var);
662  }
663 
664  std::vector<variant> made_moves;
665 
666  while(!vars.empty()) {
667 
668  if(vars.top().is_null()) {
669  vars.pop();
670  continue;
671  }
672 
673  if(auto action = vars.top().try_convert<action_callable>()) {
674  variant res = action->execute_self(*this);
675  if(res.is_int() && res.as_bool()) {
676  made_moves.push_back(vars.top());
677  }
678  } else if(vars.top().is_string() && vars.top().as_string() == "continue") {
679 // if(infinite_loop_guardian_.continue_check()) {
680  made_moves.push_back(vars.top());
681 // } else {
682  //too many calls in a row - possible infinite loop
683 // ERR_SF << "ERROR #5001 while executing 'continue' formula keyword" << std::endl;
684 
685 // if(safe_call)
686 // error = variant(new game_logic::safe_call_result(nullptr, 5001));
687 // }
688  } else if(vars.top().is_string() && (vars.top().as_string() == "end_turn" || vars.top().as_string() == "end")) {
689  break;
690  } else {
691  //this information is unneeded when evaluating formulas from commandline
692  ERR_SF << "UNRECOGNIZED MOVE: " << vars.top().to_debug_string() << std::endl;
693  }
694 
695  vars.pop();
696  }
697 
698  return variant(made_moves);
699 }
700 
701 }
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
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:614
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:39
int as_int() const
Definition: variant.cpp:292
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:594
bool is_string() const
Definition: variant.hpp:66
bool is_callable() const
Definition: variant.hpp:64
variant operator-() const
Definition: variant.cpp:478
const std::map< variant, variant > & as_map() const
Definition: variant.cpp:331
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:441
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:325
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:319
bool operator<=(const variant &) const
Definition: variant.cpp:527
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:301
std::ostringstream wrapper.
Definition: formatter.hpp:38
static std::string get()
Definition: function.cpp:51
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:629
variant list_elements_add(const variant &v) const
Definition: variant.cpp:537
VARIANT_TYPE type_
Definition: variant.hpp:217
bool operator!=(const variant &) const
Definition: variant.cpp:500
std::string serialize_to_string() const
Definition: variant.cpp:624
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:607
variant list_elements_mul(const variant &v) const
Definition: variant.cpp:549
variant operator/(const variant &) const
Definition: variant.cpp:406
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:587
std::string string_cast() const
Definition: variant.cpp:638
static value_base_ptr null_value(new variant_value_base)
variant list_elements_div(const variant &v) const
Definition: variant.cpp:555
VARIANT_TYPE type() const
Definition: variant.hpp:165
std::size_t i
Definition: function.cpp:933
std::vector< const_formula_callable_ptr > formula_seen_stack
bool operator>(const variant &) const
Definition: variant.cpp:532
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:561
variant operator+(const variant &) const
Definition: variant.cpp:337
double t
Definition: astarsearch.cpp:64
Definition: contexts.hpp:42
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:505
std::string message
Definition: exceptions.hpp:31
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:314
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:522
variant operator[](std::size_t n) const
Definition: variant.cpp:183
variant operator^(const variant &) const
Definition: variant.cpp:462
bool is_empty() const
Definition: variant.cpp:265
variant list_elements_sub(const variant &v) const
Definition: variant.cpp:543
variant operator*(const variant &) const
Definition: variant.cpp:383
bool operator==(const variant &) const
Definition: variant.cpp:487
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643