The Battle for Wesnoth  1.15.12+dev
function.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 "formula/function.hpp"
16 
17 #include "color.hpp"
18 #include "formula/callable_objects.hpp"
19 #include "formula/debugger.hpp"
20 #include "game_config.hpp"
21 #include "game_display.hpp"
22 #include "global.hpp"
23 #include "log.hpp"
24 
25 #include <boost/math/constants/constants.hpp>
26 #include <cctype>
27 #include <deque>
28 
29 using namespace boost::math::constants;
30 
31 static lg::log_domain log_engine("engine");
32 #define DBG_NG LOG_STREAM(debug, log_engine)
33 static lg::log_domain log_scripting_formula("scripting/formula");
34 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
35 #define WRN_SF LOG_STREAM(warn, log_scripting_formula)
36 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
37 
38 namespace wfl
39 {
40 /**
41  * For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL functions being evaluated.
42  *
43  * Two C++ threads might be evaluating WFL at the same; declaring this thread_local is a quick bugfix which should probably be replaced
44  * by having a context-object for each WFL evaluation.
45  */
46 thread_local static std::deque<std::string> call_stack;
47 
48 call_stack_manager::call_stack_manager(const std::string& str)
49 {
50  call_stack.push_back(str);
51 }
52 
53 call_stack_manager::~call_stack_manager()
54 {
55  call_stack.pop_back();
56 }
57 
59 {
60  std::ostringstream res;
61  for(const auto& frame : call_stack) {
62  if(!frame.empty()) {
63  res << " " << frame << "\n";
64  }
65  }
66 
67  return res.str();
68 }
69 
70 std::string function_expression::str() const
71 {
72  std::stringstream s;
73  s << get_name();
74  s << '(';
75  bool first_arg = true;
76  for(expression_ptr a : args()) {
77  if(!first_arg) {
78  s << ',';
79  } else {
80  first_arg = false;
81  }
82  s << a->str();
83  }
84  s << ')';
85  return s.str();
86 }
87 
88 namespace builtins
89 {
91 {
92  std::shared_ptr<formula_debugger> fdbp;
93  bool need_wrapper = false;
94 
95  if(fdb == nullptr) {
96  fdbp.reset(new formula_debugger());
97  fdb = fdbp.get();
98  need_wrapper = true;
99  }
100 
101  if(args().size() == 1) {
102  if(!need_wrapper) {
103  return args()[0]->evaluate(variables, fdb);
104  } else {
105  return wrapper_formula(args()[0]).evaluate(variables, fdb);
106  }
107  }
108 
109  return wrapper_formula().evaluate(variables, fdb);
110 }
111 
113 {
114  variant var = args()[0]->evaluate(variables, fdb);
115 
116  auto callable = var.as_callable();
117  formula_input_vector inputs = callable->inputs();
118 
119  std::vector<variant> res;
120  for(std::size_t i = 0; i < inputs.size(); ++i) {
121  const formula_input& input = inputs[i];
122  res.emplace_back(input.name);
123  }
124 
125  return variant(res);
126 }
127 
129 {
130  for(std::size_t n = 0; n < args().size() - 1; n += 2) {
131  if(args()[n]->evaluate(variables, fdb).as_bool()) {
132  return args()[n + 1]->evaluate(variables, fdb);
133  }
134  }
135 
136  if((args().size() % 2) != 0) {
137  return args().back()->evaluate(variables, fdb);
138  } else {
139  return variant();
140  }
141 }
142 
143 DEFINE_WFL_FUNCTION(switch, 3, -1)
144 {
145  variant var = args()[0]->evaluate(variables, fdb);
146 
147  for(std::size_t n = 1; n < args().size() - 1; n += 2) {
148  variant val = args()[n]->evaluate(variables, fdb);
149 
150  if(val == var) {
151  return args()[n + 1]->evaluate(variables, fdb);
152  }
153  }
154 
155  if((args().size() % 2) == 0) {
156  return args().back()->evaluate(variables, fdb);
157  } else {
158  return variant();
159  }
160 }
161 
163 {
164  const variant input = args()[0]->evaluate(variables, fdb);
165  if(input.is_decimal()) {
166  const int n = input.as_decimal();
167  return variant(n >= 0 ? n : -n, variant::DECIMAL_VARIANT);
168  } else {
169  const int n = input.as_int();
170  return variant(n >= 0 ? n : -n);
171  }
172 }
173 
175 {
176  variant res = args()[0]->evaluate(variables, fdb);
177  if(res.is_list()) {
178  if(res.is_empty()) {
179  throw formula_error("min(list): list is empty", "", "", 0);
180  }
181 
182  res = *std::min_element(res.begin(), res.end());
183  }
184 
185  for(std::size_t n = 1; n < args().size(); ++n) {
186  variant v = args()[n]->evaluate(variables, fdb);
187 
188  if(v.is_list()) {
189  if(v.is_empty()) {
190  continue;
191  }
192 
193  v = *std::min_element(v.begin(), v.end());
194  }
195 
196  if(res.is_null() || v < res) {
197  res = v;
198  }
199  }
200 
201  return res;
202 }
203 
205 {
206  variant res = args()[0]->evaluate(variables, fdb);
207  if(res.is_list()) {
208  if(res.is_empty()) {
209  throw formula_error("max(list): list is empty", "", "", 0);
210  }
211 
212  res = *std::max_element(res.begin(), res.end());
213  }
214 
215  for(std::size_t n = 1; n < args().size(); ++n) {
216  variant v = args()[n]->evaluate(variables, fdb);
217 
218  if(v.is_list()) {
219  if(v.is_empty()) {
220  continue;
221  }
222 
223  v = *std::max_element(v.begin(), v.end());
224  }
225 
226  if(res.is_null() || v > res) {
227  res = v;
228  }
229  }
230 
231  return res;
232 }
233 
234 namespace
235 {
236 void display_float(const map_location& location, const std::string& text)
237 {
238  game_display::get_singleton()->float_label(location, text, color_t(255, 0, 0));
239 }
240 } // end anon namespace
241 
242 DEFINE_WFL_FUNCTION(debug_float, 2, 3)
243 {
244  const args_list& arguments = args();
245  const variant var0 = arguments[0]->evaluate(variables, fdb);
246  const variant var1 = arguments[1]->evaluate(variables, fdb);
247 
248  const map_location location = var0.convert_to<location_callable>()->loc();
249  std::string text;
250 
251  if(arguments.size() == 2) {
252  text = var1.to_debug_string();
253  display_float(location, text);
254  return var1;
255  } else {
256  const variant var2 = arguments[2]->evaluate(variables, fdb);
257  text = var1.string_cast() + var2.to_debug_string();
258  display_float(location, text);
259  return var2;
260  }
261 }
262 
263 DEFINE_WFL_FUNCTION(debug_print, 1, 2)
264 {
265  const variant var1 = args()[0]->evaluate(variables, fdb);
266 
267  std::string str1, str2;
268 
269  if(args().size() == 1) {
270  str1 = var1.to_debug_string(true);
271 
272  LOG_SF << str1 << std::endl;
273 
276  std::time(nullptr), "WFL", 0, str1, events::chat_handler::MESSAGE_PUBLIC, false);
277  }
278 
279  return var1;
280  } else {
281  str1 = var1.string_cast();
282 
283  const variant var2 = args()[1]->evaluate(variables, fdb);
284  str2 = var2.to_debug_string(true);
285 
286  LOG_SF << str1 << ": " << str2 << std::endl;
287 
290  std::time(nullptr), str1, 0, str2, events::chat_handler::MESSAGE_PUBLIC, false);
291  }
292 
293  return var2;
294  }
295 }
296 
297 DEFINE_WFL_FUNCTION(debug_profile, 1, 2)
298 {
299  std::string speaker = "WFL";
300  int i_value = 0;
301 
302  if(args().size() == 2) {
303  speaker = args()[0]->evaluate(variables, fdb).string_cast();
304  i_value = 1;
305  }
306 
307  const variant value = args()[i_value]->evaluate(variables, fdb);
308  long run_time = 0;
309 
310  for(int i = 1; i < 1000; i++) {
311  const long start = SDL_GetTicks();
312  args()[i_value]->evaluate(variables, fdb);
313  run_time += SDL_GetTicks() - start;
314  }
315 
316  std::ostringstream str;
317  str << "Evaluated in " << (run_time / 1000.0) << " ms on average";
318 
319  LOG_SF << speaker << ": " << str.str() << std::endl;
320 
323  std::time(nullptr), speaker, 0, str.str(), events::chat_handler::MESSAGE_PUBLIC, false);
324  }
325 
326  return value;
327 }
328 
330 {
331  const variant map = args()[0]->evaluate(variables, fdb);
332  return map.get_keys();
333 }
334 
335 DEFINE_WFL_FUNCTION(values, 1, 1)
336 {
337  const variant map = args()[0]->evaluate(variables, fdb);
338  return map.get_values();
339 }
340 
341 DEFINE_WFL_FUNCTION(tolist, 1, 1)
342 {
343  const variant var = args()[0]->evaluate(variables, fdb);
344 
345  std::vector<variant> tmp;
346  for(variant_iterator it = var.begin(); it != var.end(); ++it) {
347  tmp.push_back(*it);
348  }
349 
350  return variant(tmp);
351 }
352 
354 {
355  const variant var_1 = args()[0]->evaluate(variables, fdb);
356 
357  std::map<variant, variant> tmp;
358 
359  if(args().size() == 2) {
360  const variant var_2 = args()[1]->evaluate(variables, fdb);
361  if(var_1.num_elements() != var_2.num_elements()) {
362  return variant();
363  }
364 
365  for(std::size_t i = 0; i < var_1.num_elements(); ++i) {
366  tmp[var_1[i]] = var_2[i];
367  }
368  } else {
369  for(variant_iterator it = var_1.begin(); it != var_1.end(); ++it) {
370  if(auto kv = (*it).try_convert<key_value_pair>()) {
371  tmp[kv->query_value("key")] = kv->query_value("value");
372  } else {
373  auto map_it = tmp.find(*it);
374 
375  if(map_it == tmp.end()) {
376  tmp[*it] = variant(1);
377  } else {
378  map_it->second = variant(map_it->second.as_int() + 1);
379  }
380  }
381  }
382  }
383 
384  return variant(tmp);
385 }
386 
387 DEFINE_WFL_FUNCTION(substring, 2, 3)
388 {
389  std::string result = args()[0]->evaluate(variables, fdb).as_string();
390 
391  int offset = args()[1]->evaluate(variables, fdb).as_int();
392  if(offset < 0) {
393  offset += result.size();
394 
395  if(offset < 0) {
396  offset = 0;
397  }
398  } else {
399  if(static_cast<std::size_t>(offset) >= result.size()) {
400  return variant(std::string());
401  }
402  }
403 
404  if(args().size() > 2) {
405  int size = args()[2]->evaluate(variables, fdb).as_int();
406 
407  if(size < 0) {
408  size = -size;
409  offset = std::max(0, offset - size + 1);
410  }
411 
412  return variant(result.substr(offset, size));
413  }
414 
415  return variant(result.substr(offset));
416 }
417 
418 DEFINE_WFL_FUNCTION(replace, 3, 4)
419 {
420  std::string result = args()[0]->evaluate(variables, fdb).as_string();
421  std::string replacement = args().back()->evaluate(variables, fdb).as_string();
422 
423  int offset = args()[1]->evaluate(variables, fdb).as_int();
424  if(offset < 0) {
425  offset += result.size();
426 
427  if(offset < 0) {
428  offset = 0;
429  }
430  } else {
431  if(static_cast<std::size_t>(offset) >= result.size()) {
432  return variant(result);
433  }
434  }
435 
436  if(args().size() > 3) {
437  int size = args()[2]->evaluate(variables, fdb).as_int();
438 
439  if(size < 0) {
440  size = -size;
441  offset = std::max(0, offset - size + 1);
442  }
443 
444  return variant(result.replace(offset, size, replacement));
445  }
446 
447  return variant(result.replace(offset, std::string::npos, replacement));
448 }
449 
451 {
452  std::string result = args()[0]->evaluate(variables, fdb).as_string();
453  std::string insert = args().back()->evaluate(variables, fdb).as_string();
454 
455  int offset = args()[1]->evaluate(variables, fdb).as_int();
456  if(offset < 0) {
457  offset += result.size();
458 
459  if(offset < 0) {
460  offset = 0;
461  }
462  } else if(static_cast<std::size_t>(offset) >= result.size()) {
463  return variant(result + insert);
464  }
465 
466  return variant(result.insert(offset, insert));
467 }
468 
469 DEFINE_WFL_FUNCTION(length, 1, 1)
470 {
471  return variant(args()[0]->evaluate(variables, fdb).as_string().length());
472 }
473 
474 DEFINE_WFL_FUNCTION(concatenate, 1, -1)
475 {
476  std::string result;
477  for(expression_ptr arg : args()) {
478  result += arg->evaluate(variables, fdb).string_cast();
479  }
480 
481  return variant(result);
482 }
483 
485 {
486  std::string str = args()[0]->evaluate(variables, fdb).as_string();
487  std::transform(str.begin(), str.end(), str.begin(), static_cast<int (*)(int)>(std::toupper));
488  return variant(str);
489 }
490 
492 {
493  std::string str = args()[0]->evaluate(variables, fdb).as_string();
494  std::transform(str.begin(), str.end(), str.begin(), static_cast<int (*)(int)>(std::tolower));
495  return variant(str);
496 }
497 
499 {
500  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
501  const double result = std::sin(angle * pi<double>() / 180.0);
502  return variant(result, variant::DECIMAL_VARIANT);
503 }
504 
506 {
507  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
508  const double result = std::cos(angle * pi<double>() / 180.0);
509  return variant(result, variant::DECIMAL_VARIANT);
510 }
511 
513 {
514  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
515  const double result = std::tan(angle * pi<double>() / 180.0);
516  if(std::isnan(result) || result <= INT_MIN || result >= INT_MAX) {
517  return variant();
518  }
519 
520  return variant(result, variant::DECIMAL_VARIANT);
521 }
522 
524 {
525  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
526  const double result = std::asin(num) * 180.0 / pi<double>();
527  if(std::isnan(result)) {
528  return variant();
529  }
530 
531  return variant(result, variant::DECIMAL_VARIANT);
532 }
533 
535 {
536  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
537  const double result = std::acos(num) * 180.0 / pi<double>();
538  if(std::isnan(result)) {
539  return variant();
540  }
541 
542  return variant(result, variant::DECIMAL_VARIANT);
543 }
544 
546 {
547  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
548  const double result = std::atan(num) * 180.0 / pi<double>();
549  return variant(result, variant::DECIMAL_VARIANT);
550 }
551 
553 {
554  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
555  const double result = std::sqrt(num);
556  if(std::isnan(result)) {
557  return variant();
558  }
559 
560  return variant(result, variant::DECIMAL_VARIANT);
561 }
562 
564 {
565  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
566  const double result = num < 0 ? -std::pow(-num, 1.0 / 3.0) : std::pow(num, 1.0 / 3.0);
567  return variant(result, variant::DECIMAL_VARIANT);
568 }
569 
571 {
572  const double base = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
573  const double root = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
574  const double result = base < 0 && std::fmod(root, 2) == 1 ? -std::pow(-base, 1.0 / root) : std::pow(base, 1.0 / root);
575  if(std::isnan(result)) {
576  return variant();
577  }
578 
579  return variant(result, variant::DECIMAL_VARIANT);
580 }
581 
583 {
584  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
585  if(args().size() == 1) {
586  const double result = std::log(num);
587  if(std::isnan(result)) {
588  return variant();
589  }
590 
591  return variant(result, variant::DECIMAL_VARIANT);
592  }
593 
594  const double base = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
595  const double result = std::log(num) / std::log(base);
596  if(std::isnan(result)) {
597  return variant();
598  }
599 
600  return variant(result, variant::DECIMAL_VARIANT);
601 }
602 
604 {
605  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
606  const double result = std::exp(num);
607  if(result == 0 || result >= INT_MAX) {
608  // These are range errors rather than NaNs,
609  // but I figure it's better than returning INT_MIN.
610  return variant();
611  }
612 
613  return variant(result, variant::DECIMAL_VARIANT);
614 }
615 
617 {
618  UNUSED(variables);
619  UNUSED(fdb);
620  return variant(pi<double>(), variant::DECIMAL_VARIANT);
621 }
622 
624 {
625  const double x = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
626  const double y = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
627  return variant(std::hypot(x, y), variant::DECIMAL_VARIANT);
628 }
629 
630 DEFINE_WFL_FUNCTION(index_of, 2, 2)
631 {
632  const variant value = args()[0]->evaluate(variables, fdb);
633  const variant list = args()[1]->evaluate(variables, fdb);
634 
635  for(std::size_t i = 0; i < list.num_elements(); ++i) {
636  if(list[i] == value) {
637  return variant(i);
638  }
639  }
640 
641  return variant(-1);
642 }
643 
644 DEFINE_WFL_FUNCTION(choose, 2, 3)
645 {
646  const variant items = args()[0]->evaluate(variables, fdb);
647  variant max_value;
648  variant_iterator max;
649 
650  if(args().size() == 2) {
651  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
652  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
653 
654  if(max == variant_iterator() || val > max_value) {
655  max = it;
656  max_value = val;
657  }
658  }
659  } else {
660  map_formula_callable self_callable;
661  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
662 
663  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
664  self_callable.add(self, *it);
665 
666  const variant val = args().back()->evaluate(
667  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
668 
669  if(max == variant_iterator() || val > max_value) {
670  max = it;
671  max_value = val;
672  }
673  }
674  }
675 
676  if(max == variant_iterator()) {
677  return variant();
678  }
679 
680  return *max;
681 }
682 
684 {
685  const int value = args()[0]->evaluate(variables, fdb).as_int() % 1000;
686  const double angle = 2.0 * pi<double>() * (static_cast<double>(value) / 1000.0);
687  return variant(static_cast<int>(std::sin(angle) * 1000.0));
688 }
689 
690 namespace
691 {
692 class variant_comparator : public formula_callable
693 {
694 public:
695  variant_comparator(const expression_ptr& expr, const formula_callable& fallback)
696  : expr_(expr)
697  , fallback_(&fallback)
698  , a_()
699  , b_()
700  {
701  }
702 
703  bool operator()(const variant& a, const variant& b) const
704  {
705  a_ = a;
706  b_ = b;
707  return expr_->evaluate(*this).as_bool();
708  }
709 
710 private:
711  variant get_value(const std::string& key) const
712  {
713  if(key == "a") {
714  return a_;
715  } else if(key == "b") {
716  return b_;
717  } else {
718  return fallback_->query_value(key);
719  }
720  }
721 
722  void get_inputs(formula_input_vector& inputs) const
723  {
724  fallback_->get_inputs(inputs);
725  }
726 
728  const formula_callable* fallback_;
729  mutable variant a_, b_;
730 };
731 } // end anon namespace
732 
734 {
735  variant list = args()[0]->evaluate(variables, fdb);
736 
737  std::vector<variant> vars;
738  vars.reserve(list.num_elements());
739 
740  for(std::size_t n = 0; n != list.num_elements(); ++n) {
741  vars.push_back(list[n]);
742  }
743 
744  if(args().size() == 1) {
745  std::sort(vars.begin(), vars.end());
746  } else {
747  std::sort(vars.begin(), vars.end(), variant_comparator(args()[1], variables));
748  }
749 
750  return variant(vars);
751 }
752 
754 {
755  const variant& arg = args()[0]->evaluate(variables, fdb);
756 
757  if(arg.is_string()) {
758  std::string str = args()[0]->evaluate(variables, fdb).as_string();
759  std::reverse(str.begin(), str.end());
760 
761  return variant(str);
762  } else if(arg.is_list()) {
763  std::vector<variant> list = args()[0]->evaluate(variables, fdb).as_list();
764  std::reverse(list.begin(), list.end());
765 
766  return variant(list);
767  }
768 
769  return variant();
770 }
771 
772 DEFINE_WFL_FUNCTION(contains_string, 2, 2)
773 {
774  std::string str = args()[0]->evaluate(variables, fdb).as_string();
775  std::string key = args()[1]->evaluate(variables, fdb).as_string();
776 
777  return variant(str.find(key) != std::string::npos);
778 }
779 
780 DEFINE_WFL_FUNCTION(find_string, 2, 2)
781 {
782  const std::string str = args()[0]->evaluate(variables, fdb).as_string();
783  const std::string key = args()[1]->evaluate(variables, fdb).as_string();
784 
785  std::size_t pos = str.find(key);
786  return variant(static_cast<int>(pos));
787 }
788 
789 DEFINE_WFL_FUNCTION(filter, 2, 3)
790 {
791  std::vector<variant> list_vars;
792  std::map<variant, variant> map_vars;
793 
794  const variant items = args()[0]->evaluate(variables, fdb);
795 
796  if(args().size() == 2) {
797  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
798  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
799 
800  if(val.as_bool()) {
801  if(items.is_map()) {
802  map_vars[(*it).get_member("key")] = (*it).get_member("value");
803  } else {
804  list_vars.push_back(*it);
805  }
806  }
807  }
808  } else {
809  map_formula_callable self_callable;
810  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
811 
812  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
813  self_callable.add(self, *it);
814 
815  const variant val = args()[2]->evaluate(
816  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
817 
818  if(val.as_bool()) {
819  if(items.is_map()) {
820  map_vars[(*it).get_member("key")] = (*it).get_member("value");
821  } else {
822  list_vars.push_back(*it);
823  }
824  }
825  }
826  }
827 
828  if(items.is_map()) {
829  return variant(map_vars);
830  }
831 
832  return variant(list_vars);
833 }
834 
836 {
837  const variant items = args()[0]->evaluate(variables, fdb);
838 
839  if(args().size() == 2) {
840  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
841  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
842  if(val.as_bool()) {
843  return *it;
844  }
845  }
846  } else {
847  map_formula_callable self_callable;
848  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
849 
850  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
851  self_callable.add(self, *it);
852 
853  const variant val = args().back()->evaluate(
854  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
855 
856  if(val.as_bool()) {
857  return *it;
858  }
859  }
860  }
861 
862  return variant();
863 }
864 
866 {
867  std::vector<variant> list_vars;
868  std::map<variant, variant> map_vars;
869  const variant items = args()[0]->evaluate(variables, fdb);
870 
871  if(args().size() == 2) {
872  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
873  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
874  if(items.is_map()) {
875  map_vars[(*it).get_member("key")] = val;
876  } else {
877  list_vars.push_back(val);
878  }
879  }
880  } else {
881  map_formula_callable self_callable;
882  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
883 
884  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
885  self_callable.add(self, *it);
886 
887  const variant val = args().back()->evaluate(
888  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
889 
890  if(items.is_map()) {
891  map_vars[(*it).get_member("key")] = val;
892  } else {
893  list_vars.push_back(val);
894  }
895  }
896  }
897 
898  if(items.is_map()) {
899  return variant(map_vars);
900  }
901 
902  return variant(list_vars);
903 }
904 
905 DEFINE_WFL_FUNCTION(take_while, 2, 2)
906 {
907  const variant& items = args()[0]->evaluate(variables, fdb);
908 
909  variant_iterator it = items.begin();
910  for(; it != items.end(); ++it) {
911  const variant matches = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
912 
913  if(!matches.as_bool()) {
914  break;
915  }
916  }
917 
918  std::vector<variant> result(items.begin(), it);
919  return variant(result);
920 }
921 
922 namespace
923 {
924 struct indexer
925 {
926  explicit indexer(std::size_t i)
927  : i(i)
928  {
929  }
930 
931  variant operator()(const variant& v) const
932  {
933  if(i >= v.num_elements()) {
934  return variant();
935  } else {
936  return v[i];
937  }
938  }
939 
940  std::size_t i;
941 };
942 
943 /** @todo: replace with lambda? */
944 struct comparator
945 {
946  bool operator()(const variant& a, const variant& b) const
947  {
948  return a.num_elements() < b.num_elements();
949  }
950 };
951 
952 std::vector<variant> get_input(
953  const function_expression::args_list& args,
954  const formula_callable& variables,
955  formula_debugger* fdb)
956 {
957  if(args.size() == 1) {
958  const variant list = args[0]->evaluate(variables, fdb);
959  return std::vector<variant>(list.begin(), list.end());
960  } else {
961  std::vector<variant> input;
962  input.reserve(args.size());
963 
964  for(expression_ptr expr : args) {
965  input.push_back(expr->evaluate(variables, fdb));
966  }
967 
968  return input;
969  }
970 }
971 } // end anon namespace
972 
974 {
975  const std::vector<variant> input = get_input(args(), variables, fdb);
976  std::vector<variant> output;
977 
978  // So basically this does [[a,b,c],[d,e,f],[x,y,z]] -> [[a,d,x],[b,e,y],[c,f,z]]
979  // Or [[a,b,c,d],[x,y,z]] -> [[a,x],[b,y],[c,z],[d,null()]]
980  std::size_t max_i = std::max_element(input.begin(), input.end(), comparator())->num_elements();
981  output.reserve(max_i);
982 
983  for(std::size_t i = 0; i < max_i; i++) {
984  std::vector<variant> elem(input.size());
985  std::transform(input.begin(), input.end(), elem.begin(), indexer(i));
986  output.emplace_back(elem);
987  }
988 
989  return variant(output);
990 }
991 
992 DEFINE_WFL_FUNCTION(reduce, 2, 3)
993 {
994  const variant items = args()[0]->evaluate(variables, fdb);
995  const variant initial = args().size() == 2 ? variant() : args()[1]->evaluate(variables, fdb);
996 
997  if(items.num_elements() == 0) {
998  return initial;
999  }
1000 
1001  variant_iterator it = items.begin();
1002  variant res(initial.is_null() ? *it : initial);
1003  if(res != initial) {
1004  ++it;
1005  }
1006 
1007  map_formula_callable self_callable;
1008  for(; it != items.end(); ++it) {
1009  self_callable.add("a", res);
1010  self_callable.add("b", *it);
1011  res = args().back()->evaluate(
1012  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
1013  }
1014 
1015  return res;
1016 }
1017 
1019 {
1020  variant res(0);
1021  const variant items = args()[0]->evaluate(variables, fdb);
1022  if(items.num_elements() > 0) {
1023  if(items[0].is_list()) {
1024  std::vector<variant> tmp;
1025  res = variant(tmp);
1026  if(args().size() >= 2) {
1027  res = args()[1]->evaluate(variables, fdb);
1028  if(!res.is_list())
1029  return variant();
1030  }
1031  } else if(items[0].is_map()) {
1032  std::map<variant, variant> tmp;
1033  res = variant(tmp);
1034  if(args().size() >= 2) {
1035  res = args()[1]->evaluate(variables, fdb);
1036  if(!res.is_map())
1037  return variant();
1038  }
1039  } else {
1040  if(args().size() >= 2) {
1041  res = args()[1]->evaluate(variables, fdb);
1042  }
1043  }
1044  }
1045 
1046  for(std::size_t n = 0; n != items.num_elements(); ++n) {
1047  res = res + items[n];
1048  }
1049 
1050  return res;
1051 }
1052 
1054 {
1055  const variant items = args()[0]->evaluate(variables, fdb);
1056  variant_iterator it = items.begin();
1057  if(it == items.end()) {
1058  return variant();
1059  }
1060 
1061  if(args().size() == 1) {
1062  return *it;
1063  }
1064 
1065  const int n = items.num_elements(), req = args()[1]->evaluate(variables, fdb).as_int();
1066  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1067 
1068  variant_iterator end = it;
1069  std::advance(end, count);
1070 
1071  std::vector<variant> res;
1072  std::copy(it, end, std::back_inserter(res));
1073  return variant(res);
1074 }
1075 
1077 {
1078  const variant items = args()[0]->evaluate(variables, fdb);
1079  variant_iterator it = items.end();
1080  if(it == items.begin()) {
1081  return variant();
1082  }
1083 
1084  if(args().size() == 1) {
1085  return *--it;
1086  }
1087 
1088  const int n = items.num_elements(), req = args()[1]->evaluate(variables, fdb).as_int();
1089  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1090 
1091  std::advance(it, -count);
1092  std::vector<variant> res;
1093 
1094  std::copy(it, items.end(), std::back_inserter(res));
1095  return variant(res);
1096 }
1097 
1099 {
1100  const variant items = args()[0]->evaluate(variables, fdb);
1101  return variant(static_cast<int>(items.num_elements()));
1102 }
1103 
1105 {
1106  if(!args().empty()) {
1107  for(std::size_t i = 0; i < args().size(); ++i) {
1108  args()[i]->evaluate(variables, fdb);
1109  }
1110  }
1111 
1112  return variant();
1113 }
1114 
1116 {
1117  variant decimal = args()[0]->evaluate(variables, fdb);
1118  int d = decimal.as_decimal();
1119 
1120  if((d >= 0) && (d % 1000 != 0)) {
1121  d /= 1000;
1122  return variant(++d);
1123  } else {
1124  d /= 1000;
1125  return variant(d);
1126  }
1127 }
1128 
1130 {
1131  variant decimal = args()[0]->evaluate(variables, fdb);
1132  int d = decimal.as_decimal();
1133  int f = d % 1000;
1134 
1135  if(f >= 500) {
1136  d /= 1000;
1137  return variant(++d);
1138  } else if(f <= -500) {
1139  d /= 1000;
1140  return variant(--d);
1141  } else {
1142  d /= 1000;
1143  return variant(d);
1144  }
1145 }
1146 
1148 {
1149  variant decimal = args()[0]->evaluate(variables, fdb);
1150  int d = decimal.as_decimal();
1151 
1152  if((d < 0) && (d % 1000 != 0)) {
1153  d /= 1000;
1154  return variant(--d);
1155  } else {
1156  d /= 1000;
1157  return variant(d);
1158  }
1159 }
1160 
1162 {
1163  variant decimal = args()[0]->evaluate(variables, fdb);
1164  int d = decimal.as_int();
1165 
1166  return variant(d);
1167 }
1168 
1170 {
1171  variant decimal = args()[0]->evaluate(variables, fdb);
1172  int d = decimal.as_decimal();
1173 
1174  d %= 1000;
1175  return variant(d, variant::DECIMAL_VARIANT);
1176 }
1177 
1179 {
1180  variant decimal = args()[0]->evaluate(variables, fdb);
1181  int d = decimal.as_decimal();
1182 
1183  if(d != 0) {
1184  d = d > 0 ? 1 : -1;
1185  }
1186 
1187  return variant(d);
1188 }
1189 
1190 DEFINE_WFL_FUNCTION(as_decimal, 1, 1)
1191 {
1192  variant decimal = args()[0]->evaluate(variables, fdb);
1193  int d = decimal.as_decimal();
1194 
1195  return variant(d, variant::DECIMAL_VARIANT);
1196 }
1197 
1199 {
1200  return variant(std::make_shared<location_callable>(map_location(
1201  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "loc:x")).as_int(),
1202  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "loc:y")).as_int(), wml_loc()
1203  )));
1204 }
1205 
1207 {
1208  return variant(std::make_shared<key_value_pair>(
1209  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "pair:key")),
1210  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "pair_value"))
1211  ));
1212 }
1213 
1215 {
1216  const map_location loc1 = args()[0]
1217  ->evaluate(variables, add_debug_info(fdb, 0, "distance_between:location_A"))
1218  .convert_to<location_callable>()
1219  ->loc();
1220 
1221  const map_location loc2 = args()[1]
1222  ->evaluate(variables, add_debug_info(fdb, 1, "distance_between:location_B"))
1223  .convert_to<location_callable>()
1224  ->loc();
1225 
1226  return variant(distance_between(loc1, loc2));
1227 }
1228 
1229 DEFINE_WFL_FUNCTION(adjacent_locs, 1, 1)
1230 {
1231  const map_location loc = args()[0]
1232  ->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location"))
1233  .convert_to<location_callable>()
1234  ->loc();
1235 
1236  std::vector<variant> v;
1237  for(const map_location& adj : get_adjacent_tiles(loc)) {
1238  v.emplace_back(std::make_shared<location_callable>(adj));
1239  }
1240 
1241  return variant(v);
1242 }
1243 
1244 DEFINE_WFL_FUNCTION(are_adjacent, 2, 2)
1245 {
1246  const map_location loc1 = args()[0]
1247  ->evaluate(variables, add_debug_info(fdb, 0, "are_adjacent:location_A"))
1248  .convert_to<location_callable>()
1249  ->loc();
1250 
1251  const map_location loc2 = args()[1]
1252  ->evaluate(variables, add_debug_info(fdb, 1, "are_adjacent:location_B"))
1253  .convert_to<location_callable>()
1254  ->loc();
1255 
1256  return variant(tiles_adjacent(loc1, loc2) ? 1 : 0);
1257 }
1258 
1259 DEFINE_WFL_FUNCTION(relative_dir, 2, 2)
1260 {
1261  const map_location loc1 = args()[0]
1262  ->evaluate(variables, add_debug_info(fdb, 0, "relative_dir:location_A"))
1263  .convert_to<location_callable>()
1264  ->loc();
1265 
1266  const map_location loc2 = args()[1]
1267  ->evaluate(variables, add_debug_info(fdb, 1, "relative_dir:location_B"))
1268  .convert_to<location_callable>()
1269  ->loc();
1270 
1272 }
1273 
1274 DEFINE_WFL_FUNCTION(direction_from, 2, 3)
1275 {
1276  const map_location loc = args()[0]
1277  ->evaluate(variables, add_debug_info(fdb, 0, "direction_from:location"))
1278  .convert_to<location_callable>()
1279  ->loc();
1280 
1281  const std::string dir_str =
1282  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "direction_from:dir")).as_string();
1283 
1284  int n = args().size() == 3
1285  ? args()[2]->evaluate(variables, add_debug_info(fdb, 2, "direction_from:count")).as_int()
1286  : 1;
1287 
1288  return variant(std::make_shared<location_callable>(loc.get_direction(map_location::parse_direction(dir_str), n)));
1289 }
1290 
1291 DEFINE_WFL_FUNCTION(rotate_loc_around, 2, 3)
1292 {
1293  const map_location center = args()[0]
1294  ->evaluate(variables, add_debug_info(fdb, 0, "direction_from:center"))
1295  .convert_to<location_callable>()
1296  ->loc();
1297 
1298  const map_location loc = args()[0]
1299  ->evaluate(variables, add_debug_info(fdb, 1, "direction_from:location"))
1300  .convert_to<location_callable>()
1301  ->loc();
1302 
1303  int n = args().size() == 3
1304  ? args()[2]->evaluate(variables, add_debug_info(fdb, 2, "direction_from:count")).as_int()
1305  : 1;
1306 
1307  return variant(std::make_shared<location_callable>(loc.rotate_right_around_center(center, n)));
1308 }
1309 
1311 {
1312  const variant& v = args()[0]->evaluate(variables, fdb);
1313  return variant(v.type_string());
1314 }
1315 
1316 } // namespace builtins
1317 
1318 namespace actions
1319 {
1320 DEFINE_WFL_FUNCTION(safe_call, 2, 2)
1321 {
1322  const variant main = args()[0]->evaluate(variables, fdb);
1323  const expression_ptr backup_formula = args()[1];
1324 
1325  return variant(std::make_shared<safe_call_callable>(main, backup_formula));
1326 }
1327 
1328 DEFINE_WFL_FUNCTION(set_var, 2, 2)
1329 {
1330  return variant(std::make_shared<set_var_callable>(
1331  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "set_var:key")).as_string(),
1332  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "set_var:value"))));
1333 }
1334 
1335 } // namespace actions
1336 
1337 variant key_value_pair::get_value(const std::string& key) const
1338 {
1339  if(key == "key") {
1340  return key_;
1341  } else if(key == "value") {
1342  return value_;
1343  }
1344 
1345  return variant();
1346 }
1347 
1348 void key_value_pair::get_inputs(formula_input_vector& inputs) const
1349 {
1350  add_input(inputs, "key");
1351  add_input(inputs, "value");
1352 }
1353 
1354 void key_value_pair::serialize_to_string(std::string& str) const
1355 {
1356  str += "pair(";
1357  str += key_.serialize_to_string();
1358  str += ",";
1359  str += value_.serialize_to_string();
1360  str += ")";
1361 }
1362 
1363 formula_function_expression::formula_function_expression(const std::string& name,
1364  const args_list& args,
1366  const_formula_ptr precondition,
1367  const std::vector<std::string>& arg_names)
1368  : function_expression(name, args, arg_names.size(), arg_names.size())
1369  , formula_(formula)
1370  , precondition_(precondition)
1371  , arg_names_(arg_names)
1372  , star_arg_(-1)
1373 {
1374  for(std::size_t n = 0; n != arg_names_.size(); ++n) {
1375  if(arg_names_[n].empty() == false && arg_names_[n].back() == '*') {
1376  arg_names_[n].resize(arg_names_[n].size() - 1);
1377  star_arg_ = n;
1378  break;
1379  }
1380  }
1381 }
1382 
1384 {
1385  static std::string indent;
1386  indent += " ";
1387 
1388  DBG_NG << indent << "executing '" << formula_->str() << "'\n";
1389 
1390  const int begin_time = SDL_GetTicks();
1391  map_formula_callable callable;
1392 
1393  for(std::size_t n = 0; n != arg_names_.size(); ++n) {
1394  variant var = args()[n]->evaluate(variables, fdb);
1395  callable.add(arg_names_[n], var);
1396 
1397  if(static_cast<int>(n) == star_arg_) {
1398  callable.set_fallback(var.as_callable());
1399  }
1400  }
1401 
1402  if(precondition_) {
1403  if(!precondition_->evaluate(callable, fdb).as_bool()) {
1404  DBG_NG << "FAILED function precondition for function '" << formula_->str() << "' with arguments: ";
1405 
1406  for(std::size_t n = 0; n != arg_names_.size(); ++n) {
1407  DBG_NG << " arg " << (n + 1) << ": " << args()[n]->evaluate(variables, fdb).to_debug_string() << "\n";
1408  }
1409  }
1410  }
1411 
1412  variant res = formula_->evaluate(callable, fdb);
1413 
1414  const int taken = SDL_GetTicks() - begin_time;
1415  DBG_NG << indent << "returning: " << taken << "\n";
1416 
1417  indent.resize(indent.size() - 2);
1418 
1419  return res;
1420 }
1421 
1423  const std::vector<expression_ptr>& args) const
1424 {
1425  return std::make_shared<formula_function_expression>(name_, args, formula_, precondition_, args_);
1426 }
1427 
1428 function_symbol_table::function_symbol_table(std::shared_ptr<function_symbol_table> parent)
1429  : parent(parent ? parent : get_builtins())
1430 {
1431 }
1432 
1433 void function_symbol_table::add_function(const std::string& name, formula_function_ptr&& fcn)
1434 {
1435  custom_formulas_.emplace(name, std::move(fcn));
1436 }
1437 
1439  const std::string& fn, const std::vector<expression_ptr>& args) const
1440 {
1441  const auto i = custom_formulas_.find(fn);
1442  if(i != custom_formulas_.end()) {
1443  return i->second->generate_function_expression(args);
1444  }
1445 
1446  if(parent) {
1447  expression_ptr res(parent->create_function(fn, args));
1448  if(res) {
1449  return res;
1450  }
1451  }
1452 
1453  throw formula_error("Unknown function: " + fn, "", "", 0);
1454 }
1455 
1456 std::set<std::string> function_symbol_table::get_function_names() const
1457 {
1458  std::set<std::string> res;
1459  if(parent) {
1460  res = parent->get_function_names();
1461  }
1462 
1463  for(const auto& formula : custom_formulas_) {
1464  res.insert(formula.first);
1465  }
1466 
1467  return res;
1468 }
1469 
1470 std::shared_ptr<function_symbol_table> function_symbol_table::get_builtins()
1471 {
1472  static function_symbol_table functions_table(builtins_tag);
1473 
1474  if(functions_table.empty()) {
1475  functions_table.parent = nullptr;
1476 
1477  using namespace builtins;
1479  DECLARE_WFL_FUNCTION(dir);
1481  DECLARE_WFL_FUNCTION(switch);
1482  DECLARE_WFL_FUNCTION(abs);
1483  DECLARE_WFL_FUNCTION(min);
1484  DECLARE_WFL_FUNCTION(max);
1485  DECLARE_WFL_FUNCTION(choose);
1486  DECLARE_WFL_FUNCTION(debug_float);
1487  DECLARE_WFL_FUNCTION(debug_print);
1488  DECLARE_WFL_FUNCTION(debug_profile);
1489  DECLARE_WFL_FUNCTION(wave);
1491  DECLARE_WFL_FUNCTION(contains_string);
1492  DECLARE_WFL_FUNCTION(find_string);
1494  DECLARE_WFL_FUNCTION(filter);
1495  DECLARE_WFL_FUNCTION(find);
1496  DECLARE_WFL_FUNCTION(map);
1497  DECLARE_WFL_FUNCTION(zip);
1498  DECLARE_WFL_FUNCTION(take_while);
1499  DECLARE_WFL_FUNCTION(reduce);
1500  DECLARE_WFL_FUNCTION(sum);
1501  DECLARE_WFL_FUNCTION(head);
1502  DECLARE_WFL_FUNCTION(tail);
1504  DECLARE_WFL_FUNCTION(null);
1505  DECLARE_WFL_FUNCTION(ceil);
1506  DECLARE_WFL_FUNCTION(floor);
1507  DECLARE_WFL_FUNCTION(trunc);
1508  DECLARE_WFL_FUNCTION(frac);
1509  DECLARE_WFL_FUNCTION(sgn);
1510  DECLARE_WFL_FUNCTION(round);
1511  DECLARE_WFL_FUNCTION(as_decimal);
1512  DECLARE_WFL_FUNCTION(pair);
1513  DECLARE_WFL_FUNCTION(loc);
1515  DECLARE_WFL_FUNCTION(adjacent_locs);
1516  DECLARE_WFL_FUNCTION(are_adjacent);
1517  DECLARE_WFL_FUNCTION(relative_dir);
1518  DECLARE_WFL_FUNCTION(direction_from);
1519  DECLARE_WFL_FUNCTION(rotate_loc_around);
1520  DECLARE_WFL_FUNCTION(index_of);
1521  DECLARE_WFL_FUNCTION(keys);
1522  DECLARE_WFL_FUNCTION(values);
1523  DECLARE_WFL_FUNCTION(tolist);
1524  DECLARE_WFL_FUNCTION(tomap);
1525  DECLARE_WFL_FUNCTION(substring);
1526  DECLARE_WFL_FUNCTION(replace);
1527  DECLARE_WFL_FUNCTION(length);
1528  DECLARE_WFL_FUNCTION(concatenate);
1529  DECLARE_WFL_FUNCTION(sin);
1530  DECLARE_WFL_FUNCTION(cos);
1531  DECLARE_WFL_FUNCTION(tan);
1532  DECLARE_WFL_FUNCTION(asin);
1533  DECLARE_WFL_FUNCTION(acos);
1534  DECLARE_WFL_FUNCTION(atan);
1535  DECLARE_WFL_FUNCTION(sqrt);
1536  DECLARE_WFL_FUNCTION(cbrt);
1537  DECLARE_WFL_FUNCTION(root);
1538  DECLARE_WFL_FUNCTION(log);
1539  DECLARE_WFL_FUNCTION(exp);
1541  DECLARE_WFL_FUNCTION(hypot);
1543  }
1544 
1545  return std::shared_ptr<function_symbol_table>(&functions_table, [](function_symbol_table*) {});
1546 }
1547 
1549  : function_symbol_table(parent)
1550 {
1551  using namespace actions;
1552  function_symbol_table& functions_table = *this;
1553  DECLARE_WFL_FUNCTION(safe_call);
1554  DECLARE_WFL_FUNCTION(set_var);
1555 }
1556 }
function_expression_ptr generate_function_expression(const std::vector< expression_ptr > &args) const
Definition: function.cpp:1422
static DIRECTION parse_direction(const std::string &str)
Definition: location.cpp:65
static lg::log_domain log_engine("engine")
std::string type_string() const
Gets string name of the current value type.
Definition: variant.hpp:147
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:226
bool is_map() const
Definition: variant.hpp:67
std::vector< expression_ptr > args_list
Definition: function.hpp:105
variant b_
Definition: function.cpp:729
#define DBG_NG
Definition: function.cpp:32
void set_fallback(const_formula_callable_ptr fallback)
Definition: callable.hpp:258
Formula AI debugger.
int as_int() const
Definition: variant.cpp:294
#define a
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
bool is_string() const
Definition: variant.hpp:66
#define LOG_SF
Definition: function.cpp:34
static lg::log_domain log_scripting_formula("scripting/formula")
std::vector< formula_input > formula_input_vector
std::shared_ptr< formula_function > formula_function_ptr
Definition: function.hpp:229
const std::vector< std::string > items
#define d
std::shared_ptr< formula_expression > expression_ptr
Definition: formula.hpp:28
bool is_list() const
Definition: variant.hpp:65
int main(int argc, char **argv)
Definition: SDLMain.mm:101
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
bool is_decimal() const
Definition: variant.hpp:63
map_location get_direction(DIRECTION dir, unsigned int n=1u) const
Definition: location.cpp:359
const std::string & as_string() const
Definition: variant.cpp:321
#define b
int as_decimal() const
Returns variant&#39;s internal representation of decimal number: ie, 1.234 is represented as 1234...
Definition: variant.cpp:303
static std::ostream & output()
Definition: log.cpp:49
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
static int str_lower(lua_State *L)
Definition: lstrlib.cpp:124
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:252
variant evaluate(const formula_callable &variables, formula_debugger *fdb=nullptr) const
Definition: function.hpp:75
map_location rotate_right_around_center(const map_location &center, int k) const
Definition: location.cpp:306
std::shared_ptr< function_expression > function_expression_ptr
Definition: function.hpp:172
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:46
static std::shared_ptr< function_symbol_table > get_builtins()
Definition: function.cpp:1470
variant_iterator end() const
Definition: variant.cpp:260
static int indent
Definition: log.cpp:42
Encapsulates the map of the game.
Definition: location.hpp:37
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
std::string string_cast() const
Definition: variant.cpp:640
const_formula_callable_ptr as_callable() const
Definition: variant.hpp:82
#define UNUSED(x)
Definition: global.hpp:30
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:502
std::shared_ptr< function_symbol_table > parent
Definition: function.hpp:251
function_symbol_table(std::shared_ptr< function_symbol_table > parent=nullptr)
Definition: function.cpp:1428
std::size_t i
Definition: function.cpp:940
action_function_symbol_table(std::shared_ptr< function_symbol_table > parent=nullptr)
Definition: function.cpp:1548
static void expr(LexState *ls, expdesc *v)
Definition: lparser.cpp:1278
static map_location::DIRECTION s
CURSOR_TYPE get()
Definition: cursor.cpp:215
const_formula_ptr precondition_
Definition: function.hpp:165
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:99
const bool & debug
#define debug(x)
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:23
static int sort(lua_State *L)
Definition: ltablib.cpp:397
variant a_
Definition: function.cpp:729
static int str_upper(lua_State *L)
Definition: lstrlib.cpp:137
std::vector< std::string > arg_names_
Definition: function.hpp:167
std::set< std::string > get_function_names() const
Definition: function.cpp:1456
const std::string name_
Definition: function.hpp:96
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
Definition: function.hpp:47
const formula_callable * fallback_
Definition: function.cpp:728
display_chat_manager & get_chat_manager()
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:61
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:545
const args_list & args() const
Definition: function.hpp:123
#define f
Definition: contexts.hpp:43
variant get_keys() const
Definition: variant.cpp:231
variant_iterator begin() const
Definition: variant.cpp:255
#define DEFINE_WFL_FUNCTION(name, min_args, max_args)
Helper macro to declare an associated class for a WFL function.
Definition: function.hpp:27
expression_ptr create_function(const std::string &fn, const std::vector< expression_ptr > &args) const
Definition: function.cpp:1438
Standard logging facilities (interface).
variant get_values() const
Definition: variant.cpp:243
void add_function(const std::string &name, formula_function_ptr &&fcn)
Definition: function.cpp:1433
EXIT_STATUS start(const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
std::size_t num_elements() const
Definition: variant.cpp:270
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:203
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
functions_map custom_formulas_
Definition: function.hpp:252
variant execute(const formula_callable &variables, formula_debugger *fdb) const
Definition: function.cpp:1383
static map_location::DIRECTION n
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:140
expression_ptr expr_
Definition: function.cpp:727
bool is_empty() const
Definition: variant.cpp:265
std::shared_ptr< T > convert_to() const
Definition: variant.hpp:99
static game_display * get_singleton()
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:645