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