The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
function.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "global.hpp"
16 
17 
18 #include "formula/callable_objects.hpp"
19 #include "formula/debugger.hpp"
20 #include "formula/function.hpp"
21 #include "game_display.hpp"
22 #include "game_config.hpp"
23 #include "log.hpp"
24 
25 #include <boost/math/constants/constants.hpp>
26 using namespace boost::math::constants;
27 
28 #ifdef HAVE_VISUAL_LEAK_DETECTOR
29 #include "vld.h"
30 #endif
31 
32 
33 static lg::log_domain log_engine("engine");
34 #define DBG_NG LOG_STREAM(debug, log_engine)
35 static lg::log_domain log_scripting_formula("scripting/formula");
36 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
37 #define WRN_SF LOG_STREAM(warn, log_scripting_formula)
38 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
39 
40 namespace game_logic {
41 
42 std::string function_expression::str() const
43 {
44  std::stringstream s;
45  s << get_name();
46  s << '(';
47  bool first_arg = true;
48  for (expression_ptr a : args()) {
49  if (!first_arg) {
50  s << ',';
51  } else {
52  first_arg = false;
53  }
54  s << a->str();
55  }
56  s << ')';
57  return s.str();
58 }
59 
60 namespace {
61 
62 class debug_function : public function_expression {
63 public:
64  explicit debug_function(const args_list& args)
65  : function_expression("debug",args, 0, 1)
66  {}
67 private:
68  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
70  bool need_wrapper = false;
71  if (fdb==nullptr) {
72  fdbp = boost::shared_ptr<formula_debugger>(new formula_debugger());
73  fdb = &*fdbp;
74  need_wrapper = true;
75 
76  }
77 
78  if (args().size()==1) {
79  if (!need_wrapper) {
80  return args()[0]->evaluate(variables,fdb);
81  } else {
82  return wrapper_formula(args()[0]).evaluate(variables,fdb);
83  }
84  } else {
85  return wrapper_formula().evaluate(variables,fdb);
86  }
87  }
88 };
89 
90 
91 class dir_function : public function_expression {
92 public:
93  explicit dir_function(const args_list& args)
94  : function_expression("dir", args, 1, 1)
95  {}
96 
97 private:
98  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
99  variant var = args()[0]->evaluate(variables, fdb);
100  const formula_callable* callable = var.as_callable();
101  callable->add_ref();
102  std::vector<formula_input> inputs = callable->inputs();
103  std::vector<variant> res;
104  for(size_t i=0; i<inputs.size(); ++i) {
105  const formula_input& input = inputs[i];
106  res.push_back(variant(input.name));
107  }
108 
109  return variant(&res);
110  }
111 };
112 
113 class if_function : public function_expression {
114 public:
115  explicit if_function(const args_list& args)
116  : function_expression("if", args, 2, -1)
117  {}
118 
119 private:
120  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
121  for(size_t n = 0; n < args().size()-1; n += 2) {
122  if( args()[n]->evaluate(variables,fdb).as_bool() ) {
123  return args()[n+1]->evaluate(variables,fdb);
124  }
125  }
126 
127  if((args().size()%2) != 0) {
128  return args().back()->evaluate(variables,fdb);
129  } else {
130  return variant();
131  }
132 
133  }
134 };
135 
136 class switch_function : public function_expression {
137 public:
138  explicit switch_function(const args_list& args)
139  : function_expression("switch", args, 3, -1)
140  {}
141 
142 private:
143  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
144  variant var = args()[0]->evaluate(variables,fdb);
145  for(size_t n = 1; n < args().size()-1; n += 2) {
146  variant val = args()[n]->evaluate(variables,fdb);
147  if(val == var) {
148  return args()[n+1]->evaluate(variables,fdb);
149  }
150  }
151 
152  if((args().size()%2) == 0) {
153  return args().back()->evaluate(variables,fdb);
154  } else {
155  return variant();
156  }
157  }
158 };
159 
160 class abs_function : public function_expression {
161 public:
162  explicit abs_function(const args_list& args)
163  : function_expression("abs", args, 1, 1)
164  {}
165 
166 private:
167  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
168  const variant input = args()[0]->evaluate(variables,fdb);
169  if(input.is_decimal()) {
170  const int n = input.as_decimal();
171  return variant(n >= 0 ? n : -n, variant::DECIMAL_VARIANT);
172  } else {
173  const int n = input.as_int();
174  return variant(n >= 0 ? n : -n);
175  }
176  }
177 };
178 
179 class min_function : public function_expression {
180 public:
181  explicit min_function(const args_list& args)
182  : function_expression("min", args, 1, -1)
183  {}
184 
185 private:
186  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
187  bool found = false;
188  variant res(0);
189  for(size_t n = 0; n != args().size(); ++n) {
190  const variant v = args()[n]->evaluate(variables,fdb);
191  if(v.is_list()) {
192  for(size_t m = 0; m != v.num_elements(); ++m) {
193  if(!found || v[m] < res) {
194  res = v[m];
195  found = true;
196  }
197  }
198  } else if(v.is_int() || v.is_decimal()) {
199  if(!found || v < res) {
200  res = v;
201  found = true;
202  }
203  }
204  }
205 
206  return res;
207  }
208 };
209 
210 class max_function : public function_expression {
211 public:
212  explicit max_function(const args_list& args)
213  : function_expression("max", args, 1, -1)
214  {}
215 
216 private:
217  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
218  bool found = false;
219  variant res(0);
220  for(size_t n = 0; n != args().size(); ++n) {
221  const variant v = args()[n]->evaluate(variables,fdb);
222  if(v.is_list()) {
223  for(size_t m = 0; m != v.num_elements(); ++m) {
224  if(!found || v[m] > res) {
225  res = v[m];
226  found = true;
227  }
228  }
229  } else if(v.is_int() || v.is_decimal()) {
230  if(!found || v > res) {
231  res = v;
232  found = true;
233  }
234  }
235  }
236 
237  return res;
238  }
239 };
240 
241 class debug_float_function : public function_expression {
242 public:
243  explicit debug_float_function(const args_list& args)
244  : function_expression("debug_float", args, 2, 3)
245  {}
246 
247 private:
248  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
249  const args_list& arguments = args();
250  const variant var0 = arguments[0]->evaluate(variables,fdb);
251  const variant var1 = arguments[1]->evaluate(variables,fdb);
252 
253  const map_location location = convert_variant<location_callable>(var0)->loc();
254  std::string text;
255 
256  if(arguments.size() == 2) {
257  text = var1.to_debug_string();
258  display_float(location,text);
259  return var1;
260  } else {
261  const variant var2 = arguments[2]->evaluate(variables,fdb);
262  text = var1.string_cast() + var2.to_debug_string();
263  display_float(location,text);
264  return var2;
265  }
266 
267  }
268 
269  void display_float(const map_location& location, const std::string& text) const{
270  game_display::get_singleton()->float_label(location, text, create_color(255,0,0));
271  }
272 };
273 
274 
275 class debug_print_function : public function_expression {
276 public:
277  explicit debug_print_function(const args_list& args)
278  : function_expression("debug_print", args, 1, 2)
279  {}
280 
281 private:
282  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
283  const variant var1 = args()[0]->evaluate(variables,fdb);
284 
285  std::string str1,str2;
286 
287  if( args().size() == 1)
288  {
289  str1 = var1.to_debug_string(nullptr, true);
290  LOG_SF << str1 << std::endl;
291  if(game_config::debug) {
293  }
294  return var1;
295  } else {
296  str1 = var1.string_cast();
297  const variant var2 = args()[1]->evaluate(variables,fdb);
298  str2 = var2.to_debug_string(nullptr, true);
299  LOG_SF << str1 << str2 << std::endl;
300  if(game_config::debug) {
302  }
303  return var2;
304  }
305  }
306 };
307 
308 class debug_profile_function : public function_expression {
309 public:
310  explicit debug_profile_function(const args_list& args)
311  : function_expression("debug_profile", args, 1, 2)
312  {}
313 
314 private:
315  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
316  std::string speaker = "WFL";
317  int i_value = 0;
318  if(args().size() == 2) {
319  speaker = args()[0]->evaluate(variables, fdb).string_cast();
320  i_value = 1;
321  }
322 
323  const variant value = args()[i_value]->evaluate(variables,fdb);
324  long run_time = 0;
325  for(int i = 1; i < 1000; i++) {
326  const long start = SDL_GetTicks();
327  args()[i_value]->evaluate(variables,fdb);
328  run_time += SDL_GetTicks() - start;
329  }
330 
331  std::ostringstream str;
332  str << "Evaluated in " << (run_time / 1000.0) << " ms on average";
333  LOG_SF << speaker << ": " << str.str() << std::endl;
334  if(game_config::debug) {
336  }
337  return value;
338  }
339 };
340 
341 class keys_function : public function_expression {
342 public:
343  explicit keys_function(const args_list& args)
344  : function_expression("keys", args, 1, 1)
345  {}
346 
347 private:
348  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
349  const variant map = args()[0]->evaluate(variables,fdb);
350  return map.get_keys();
351  }
352 };
353 
354 class values_function : public function_expression {
355 public:
356  explicit values_function(const args_list& args)
357  : function_expression("values", args, 1, 1)
358  {}
359 
360 private:
361  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
362  const variant map = args()[0]->evaluate(variables,fdb);
363  return map.get_values();
364  }
365 };
366 
367 class tolist_function : public function_expression {
368 public:
369  explicit tolist_function(const args_list& args)
370  : function_expression("tolist", args, 1, 1)
371  {}
372 
373 private:
374  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
375  const variant var = args()[0]->evaluate(variables,fdb);
376 
377  std::vector<variant> tmp;
378 
379  for(variant_iterator it = var.begin(); it != var.end(); ++it) {
380  tmp.push_back( *it );
381  }
382 
383  return variant( &tmp );
384  }
385 };
386 
387 class tomap_function : public function_expression {
388 public:
389  explicit tomap_function(const args_list& args)
390  : function_expression("tomap", args, 1, 2)
391  {}
392 
393 private:
394  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
395  const variant var_1 = args()[0]->evaluate(variables,fdb);
396 
397  std::map<variant, variant> tmp;
398 
399  if (args().size() == 2)
400  {
401  const variant var_2 = args()[1]->evaluate(variables,fdb);
402  if ( var_1.num_elements() != var_2.num_elements() )
403  return variant();
404  for(size_t i = 0; i < var_1.num_elements(); ++i )
405  tmp[ var_1[i] ] = var_2[i];
406  } else
407  {
408  for(variant_iterator it = var_1.begin(); it != var_1.end(); ++it) {
409  if (key_value_pair* kv = (*it).try_convert<key_value_pair>())
410  tmp[kv->query_value("key")] = kv->query_value("value");
411  else {
412  std::map<variant, variant>::iterator map_it = tmp.find( *it );
413  if (map_it == tmp.end()) {
414  tmp[*it] = variant(1);
415  } else {
416  map_it->second = variant(map_it->second.as_int() + 1);
417  }
418  }
419  }
420  }
421 
422  return variant( &tmp );
423  }
424 };
425 
426 class substring_function : public function_expression {
427 public:
428  explicit substring_function(const args_list& args)
429  : function_expression("substring", args, 2, 3)
430  {}
431 private:
432  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
433 
434  std::string result = args()[0]->evaluate(variables, fdb).as_string();
435 
436  int offset = args()[1]->evaluate(variables, fdb).as_int();
437  if(offset < 0) {
438  offset += result.size();
439  if(offset < 0) {
440  offset = 0;
441  }
442  } else {
443  if(static_cast<size_t>(offset) >= result.size()) {
444  return variant(std::string());
445  }
446  }
447 
448  if(args().size() > 2) {
449  int size = args()[2]->evaluate(variables, fdb).as_int();
450  if(size < 0) {
451  size = -size;
452  offset = std::max(0, offset - size + 1);
453  }
454  return variant(result.substr(offset, size));
455  } else {
456  return variant(result.substr(offset));
457  }
458  }
459 };
460 
461 class replace_function : public function_expression {
462 public:
463  explicit replace_function(const args_list& args)
464  : function_expression("replace", args, 3, 4)
465  {}
466 private:
467  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
468 
469  std::string result = args()[0]->evaluate(variables, fdb).as_string();
470  std::string replacement = args().back()->evaluate(variables, fdb).as_string();
471 
472  int offset = args()[1]->evaluate(variables, fdb).as_int();
473  if(offset < 0) {
474  offset += result.size();
475  if(offset < 0) {
476  offset = 0;
477  }
478  } else {
479  if(static_cast<size_t>(offset) >= result.size()) {
480  return variant(result);
481  }
482  }
483 
484  if(args().size() > 3) {
485  int size = args()[2]->evaluate(variables, fdb).as_int();
486  if(size < 0) {
487  size = -size;
488  offset = std::max(0, offset - size + 1);
489  }
490  return variant(result.replace(offset, size, replacement));
491  } else {
492  return variant(result.replace(offset, std::string::npos, replacement));
493  }
494  }
495 };
496 
497 class length_function : public function_expression {
498 public:
499  explicit length_function(const args_list& args)
500  : function_expression("length", args, 1, 1)
501  {}
502 private:
503  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
504  return variant(args()[0]->evaluate(variables, fdb).as_string().length());
505  }
506 };
507 
508 class concatenate_function : public function_expression {
509 public:
510  explicit concatenate_function(const args_list& args)
511  : function_expression("concatenate", args, 1, -1)
512  {}
513 private:
514  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
516 
517  for(expression_ptr arg : args()) {
518  result += arg->evaluate(variables, fdb).string_cast();
519  }
520 
521  return variant(result);
522  }
523 };
524 
525 class sin_function : public function_expression {
526 public:
527  explicit sin_function(const args_list& args)
528  : function_expression("sin", args, 1, 1)
529  {}
530 private:
531  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
532  const double angle = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
533  const double result = sin(angle * pi<double>() / 180.0);
534  return variant(result, variant::DECIMAL_VARIANT);
535  }
536 };
537 
538 class cos_function : public function_expression {
539 public:
540  explicit cos_function(const args_list& args)
541  : function_expression("cos", args, 1, 1)
542  {}
543 private:
544  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
545  const double angle = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
546  const double result = cos(angle * pi<double>() / 180.0);
547  return variant(result, variant::DECIMAL_VARIANT);
548  }
549 };
550 
551 class tan_function : public function_expression {
552 public:
553  explicit tan_function(const args_list& args)
554  : function_expression("tan", args, 1, 1)
555  {}
556 private:
557  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
558  const double angle = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
559  const double result = tan(angle * pi<double>() / 180.0);
560  if(result != result || result <= INT_MIN || result >= INT_MAX) {
561  return variant();
562  }
563  return variant(result, variant::DECIMAL_VARIANT);
564  }
565 };
566 
567 class asin_function : public function_expression {
568 public:
569  explicit asin_function(const args_list& args)
570  : function_expression("asin", args, 1, 1)
571  {}
572 
573 private:
574  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
575  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
576  const double result = asin(num) * 180.0 / pi<double>();
577  if(result != result) {
578  return variant();
579  }
580  return variant(result, variant::DECIMAL_VARIANT);
581  }
582 };
583 
584 class acos_function : public function_expression {
585 public:
586  explicit acos_function(const args_list& args)
587  : function_expression("acos", args, 1, 1)
588  {}
589 private:
590  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
591  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
592  const double result = acos(num) * 180.0 / pi<double>();
593  if(result != result) {
594  return variant();
595  }
596  return variant(result, variant::DECIMAL_VARIANT);
597  }
598 };
599 
600 class atan_function : public function_expression {
601 public:
602  explicit atan_function(const args_list& args)
603  : function_expression("acos", args, 1, 1)
604  {}
605 private:
606  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
607  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
608  const double result = atan(num) * 180.0 / pi<double>();
609  return variant(result, variant::DECIMAL_VARIANT);
610  }
611 };
612 
613 class sqrt_function : public function_expression {
614 public:
615  explicit sqrt_function(const args_list& args)
616  : function_expression("sqrt", args, 1, 1)
617  {}
618 private:
619  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
620  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
621  const double result = sqrt(num);
622  if(result != result) {
623  return variant();
624  }
625  return variant(result, variant::DECIMAL_VARIANT);
626  }
627 };
628 
629 class cbrt_function : public function_expression {
630 public:
631  explicit cbrt_function(const args_list& args)
632  : function_expression("cbrt", args, 1, 1)
633  {}
634 private:
635  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
636  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
637  const double result = num < 0 ? -pow(-num, 1.0 / 3.0) : pow(num, 1.0 / 3.0);
638  return variant(result, variant::DECIMAL_VARIANT);
639  }
640 };
641 
642 class root_function : public function_expression {
643 public:
644  explicit root_function(const args_list& args)
645  : function_expression("root", args, 2, 2)
646  {}
647 private:
648  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
649  const double base = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
650  const double root = args()[1]->evaluate(variables,fdb).as_decimal() / 1000.0;
651  const double result = base < 0 && fmod(root,2) == 1 ? -pow(-base, 1.0 / root) : pow(base, 1.0 / root);
652  if(result != result) {
653  return variant();
654  }
655  return variant(result, variant::DECIMAL_VARIANT);
656  }
657 };
658 
659 class log_function : public function_expression {
660 public:
661  explicit log_function(const args_list& args)
662  : function_expression("log", args, 1, 2)
663  {}
664 private:
665  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
666  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
667  if(args().size() == 1) {
668  const double result = log(num);
669  if(result != result) {
670  return variant();
671  }
672  return variant(result, variant::DECIMAL_VARIANT);
673  } else {
674  const double base = args()[1]->evaluate(variables,fdb).as_decimal() / 1000.0;
675  const double result = log(num) / log(base);
676  if(result != result) {
677  return variant();
678  }
679  return variant(result, variant::DECIMAL_VARIANT);
680  }
681  }
682 };
683 
684 class exp_function : public function_expression {
685 public:
686  explicit exp_function(const args_list& args)
687  : function_expression("exp", args, 1, 1)
688  {}
689 private:
690  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
691  const double num = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
692  const double result = exp(num);
693  if(result == 0 || result >= INT_MAX) {
694  // These are range errors rather than NaNs,
695  // but I figure it's better than returning INT_MIN.
696  return variant();
697  }
698  return variant(result, variant::DECIMAL_VARIANT);
699  }
700 };
701 
702 class pi_function : public function_expression {
703 public:
704  explicit pi_function(const args_list& args)
705  : function_expression("pi", args, 0, 0)
706  {}
707 private:
708  variant execute(const formula_callable&, formula_debugger*) const {
709  return variant(pi<double>(), variant::DECIMAL_VARIANT);
710  }
711 };
712 
713 class hypot_function : public function_expression {
714 public:
715  explicit hypot_function(const args_list& args)
716  : function_expression("hypot", args, 2, 2)
717  {}
718 private:
719  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
720  const double x = args()[0]->evaluate(variables,fdb).as_decimal() / 1000.0;
721  const double y = args()[1]->evaluate(variables,fdb).as_decimal() / 1000.0;
722  return variant(hypot(x,y), variant::DECIMAL_VARIANT);
723  }
724 };
725 
726 class index_of_function : public function_expression {
727 public:
728  explicit index_of_function(const args_list& args)
729  : function_expression("index_of", args, 2, 2)
730  {}
731 
732 private:
733  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
734  const variant value = args()[0]->evaluate(variables,fdb);
735  const variant list = args()[1]->evaluate(variables,fdb);
736 
737  for(size_t i = 0; i < list.num_elements(); ++i ) {
738  if( list[i] == value) {
739  return variant(i);
740  }
741  }
742 
743  return variant( -1 );
744  }
745 };
746 
747 
748 class choose_function : public function_expression {
749 public:
750  explicit choose_function(const args_list& args)
751  : function_expression("choose", args, 2, 3)
752  {}
753 
754 private:
755  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
756  const variant items = args()[0]->evaluate(variables,fdb);
757  variant max_value;
758  variant_iterator max;
759 
760  if(args().size() == 2) {
761  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
762  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables),fdb);
763  if(max == variant_iterator() || val > max_value) {
764  max = it;
765  max_value = val;
766  }
767  }
768  } else {
769  map_formula_callable self_callable;
770  self_callable.add_ref();
771  const std::string self = args()[1]->evaluate(variables,fdb).as_string();
772  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
773  self_callable.add(self, *it);
774  const variant val = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)),fdb);
775  if(max == variant_iterator() || val > max_value) {
776  max = it;
777  max_value = val;
778  }
779  }
780  }
781 
782  if(max == variant_iterator() ) {
783  return variant();
784  } else {
785  return *max;
786  }
787  }
788 };
789 
790 class wave_function : public function_expression {
791 public:
792  explicit wave_function(const args_list& args)
793  : function_expression("wave", args, 1, 1)
794  {}
795 
796 private:
797  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
798  const int value = args()[0]->evaluate(variables,fdb).as_int()%1000;
799  const double angle = 2.0 * pi<double>() * (static_cast<double>(value) / 1000.0);
800  return variant(static_cast<int>(sin(angle)*1000.0));
801  }
802 };
803 
804 namespace {
805 class variant_comparator : public formula_callable {
807  const formula_callable* fallback_;
808  mutable variant a_, b_;
809  variant get_value(const std::string& key) const {
810  if(key == "a") {
811  return a_;
812  } else if(key == "b") {
813  return b_;
814  } else {
815  return fallback_->query_value(key);
816  }
817  }
818 
819  void get_inputs(std::vector<formula_input>* inputs) const {
820  fallback_->get_inputs(inputs);
821  }
822 public:
823  variant_comparator(const expression_ptr& expr, const formula_callable& fallback) :
824  expr_(expr),
825  fallback_(&fallback),
826  a_(),
827  b_()
828  {}
829 
830  bool operator()(const variant& a, const variant& b) const {
831  a_ = a;
832  b_ = b;
833  return expr_->evaluate(*this).as_bool();
834  }
835 };
836 }
837 
838 class sort_function : public function_expression {
839 public:
840  explicit sort_function(const args_list& args)
841  : function_expression("sort", args, 1, 2)
842  {}
843 
844 private:
845  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
846  variant list = args()[0]->evaluate(variables,fdb);
847  std::vector<variant> vars;
848  vars.reserve(list.num_elements());
849  for(size_t n = 0; n != list.num_elements(); ++n) {
850  vars.push_back(list[n]);
851  }
852 
853  if(args().size() == 1) {
854  std::sort(vars.begin(), vars.end());
855  } else {
856  std::sort(vars.begin(), vars.end(), variant_comparator(args()[1], variables));
857  }
858 
859  return variant(&vars);
860  }
861 };
862 
863 class reverse_function : public function_expression {
864 public:
865  explicit reverse_function(const args_list& args)
866  : function_expression("reverse", args, 1, 1)
867  {}
868 
869 private:
870  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
871  const variant& arg = args()[0]->evaluate(variables,fdb);
872  if(arg.is_string()) {
873  std::string str = args()[0]->evaluate(variables,fdb).as_string();
874  std::reverse(str.begin(), str.end());
875  return variant(str);
876  } else if(arg.is_list()) {
877  std::vector<variant> list = args()[0]->evaluate(variables,fdb).as_list();
878  std::reverse(list.begin(), list.end());
879  return variant(&list);
880  }
881  return variant();
882  }
883 };
884 
885 class contains_string_function : public function_expression {
886 public:
887  explicit contains_string_function(const args_list& args)
888  : function_expression("contains_string", args, 2, 2)
889  {}
890 
891 private:
892  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
893  std::string str = args()[0]->evaluate(variables,fdb).as_string();
894  std::string key = args()[1]->evaluate(variables,fdb).as_string();
895 
896  return variant(str.find(key) != std::string::npos);
897  }
898 };
899 
900 class find_string_function : public function_expression {
901 public:
902  explicit find_string_function(const args_list& args)
903  : function_expression("find_string", args, 2, 2)
904  {}
905 
906 private:
907  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
908  const std::string str = args()[0]->evaluate(variables,fdb).as_string();
909  const std::string key = args()[1]->evaluate(variables,fdb).as_string();
910 
911  size_t pos = str.find(key);
912  return variant(static_cast<int>(pos));
913  }
914 };
915 
916 class filter_function : public function_expression {
917 public:
918  explicit filter_function(const args_list& args)
919  : function_expression("filter", args, 2, 3)
920  {}
921 private:
922  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
923  std::vector<variant> list_vars;
924  std::map<variant,variant> map_vars;
925 
926  const variant items = args()[0]->evaluate(variables,fdb);
927 
928  if(args().size() == 2) {
929  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
930  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables),fdb);
931  if(val.as_bool()) {
932  if (items.is_map() )
933  map_vars[ (*it).get_member("key") ] = (*it).get_member("value");
934  else
935  list_vars.push_back(*it);
936  }
937  }
938  } else {
939  map_formula_callable self_callable;
940  self_callable.add_ref();
941  const std::string self = args()[1]->evaluate(variables,fdb).as_string();
942  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
943  self_callable.add(self, *it);
944  const variant val = args()[2]->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)),fdb);
945  if(val.as_bool()) {
946  if (items.is_map() )
947  map_vars[ (*it).get_member("key") ] = (*it).get_member("value");
948  else
949  list_vars.push_back(*it);
950  }
951  }
952  }
953  if (items.is_map() )
954  return variant(&map_vars);
955  return variant(&list_vars);
956  }
957 };
958 
959 class find_function : public function_expression {
960 public:
961  explicit find_function(const args_list& args)
962  : function_expression("find", args, 2, 3)
963  {}
964 
965 private:
966  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
967  const variant items = args()[0]->evaluate(variables,fdb);
968 
969  if(args().size() == 2) {
970  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
971  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables),fdb);
972  if(val.as_bool()) {
973  return *it;
974  }
975  }
976  } else {
977  map_formula_callable self_callable;
978  self_callable.add_ref();
979  const std::string self = args()[1]->evaluate(variables,fdb).as_string();
980  for(variant_iterator it = items.begin(); it != items.end(); ++it){
981  self_callable.add(self, *it);
982  const variant val = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)),fdb);
983  if(val.as_bool()) {
984  return *it;
985  }
986  }
987  }
988 
989  return variant();
990  }
991 };
992 
993 class map_function : public function_expression {
994 public:
995  explicit map_function(const args_list& args)
996  : function_expression("map", args, 2, 3)
997  {}
998 private:
999  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1000  std::vector<variant> list_vars;
1001  std::map<variant,variant> map_vars;
1002  const variant items = args()[0]->evaluate(variables,fdb);
1003 
1004  if(args().size() == 2) {
1005  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
1006  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables),fdb);
1007  if (items.is_map() )
1008  map_vars[ (*it).get_member("key") ] = val;
1009  else
1010  list_vars.push_back(val);
1011  }
1012  } else {
1013  map_formula_callable self_callable;
1014  self_callable.add_ref();
1015  const std::string self = args()[1]->evaluate(variables,fdb).as_string();
1016  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
1017  self_callable.add(self, *it);
1018  const variant val = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)),fdb);
1019  if (items.is_map() )
1020  map_vars[ (*it).get_member("key") ] = val;
1021  else
1022  list_vars.push_back(val);
1023  }
1024  }
1025  if (items.is_map() )
1026  return variant(&map_vars);
1027  return variant(&list_vars);
1028  }
1029 };
1030 
1031 class take_while_function : public function_expression {
1032 public:
1033  explicit take_while_function(const args_list& args)
1034  : function_expression("take_while", args, 2, 2)
1035  {}
1036 private:
1037  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1038  const variant& items = args()[0]->evaluate(variables, fdb);
1039  variant_iterator it = items.begin();
1040  for(; it != items.end(); ++it) {
1041  const variant matches = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables),fdb);
1042  if (!matches.as_bool())
1043  break;
1044  }
1045  std::vector<variant> result(items.begin(), it);
1046  return variant(&result);
1047  }
1048 };
1049 
1050 class zip_function : public function_expression {
1051 public:
1052  explicit zip_function(const args_list& args)
1053  : function_expression("zip", args, 1, -1)
1054  {}
1055 private:
1056  struct indexer {
1057  size_t i;
1058  explicit indexer(size_t i) : i(i) {}
1059  variant operator()(const variant& v) {
1060  if(i >= v.num_elements()) {
1061  return variant();
1062  } else {
1063  return v[i];
1064  }
1065  }
1066  };
1067  struct comparator {
1068  bool operator()(const variant& a, const variant& b) {
1069  return a.num_elements() < b.num_elements();
1070  }
1071  };
1072  std::vector<variant> get_input(const formula_callable& variables, formula_debugger* fdb) const {
1073  if(args().size() == 1) {
1074  const variant list = args()[0]->evaluate(variables, fdb);
1075  return std::vector<variant>(list.begin(), list.end());
1076  } else {
1077  std::vector<variant> input;
1078  input.reserve(args().size());
1079  for(expression_ptr expr : args()) {
1080  input.push_back(expr->evaluate(variables, fdb));
1081  }
1082  return input;
1083  }
1084  }
1085  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1086  const std::vector<variant> input = get_input(variables, fdb);
1087  std::vector<variant> output;
1088  // So basically this does [[a,b,c],[d,e,f],[x,y,z]] -> [[a,d,x],[b,e,y],[c,f,z]]
1089  // Or [[a,b,c,d],[x,y,z]] -> [[a,x],[b,y],[c,z],[d,null()]]
1090  size_t max_i = std::max_element(input.begin(), input.end(), comparator())->num_elements();
1091  output.reserve(max_i);
1092  for(size_t i = 0; i < max_i; i++) {
1093  std::vector<variant> elem(input.size());
1094  std::transform(input.begin(), input.end(), elem.begin(), indexer(i));
1095  output.push_back(variant(&elem));
1096  }
1097  return variant(&output);
1098  }
1099 };
1100 
1101 class reduce_function : public function_expression {
1102 public:
1103  explicit reduce_function(const args_list& args)
1104  : function_expression("reduce", args, 2, 3)
1105  {}
1106 private:
1107  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1108  const variant items = args()[0]->evaluate(variables,fdb);
1109  const variant initial = args().size() == 2 ? variant() : args()[1]->evaluate(variables,fdb);
1110 
1111  if(items.num_elements() == 0)
1112  return initial;
1113 
1114  variant_iterator it = items.begin();
1115  variant res(initial.is_null() ? *it : initial);
1116  if(res != initial) {
1117  ++it;
1118  }
1119  map_formula_callable self_callable;
1120  self_callable.add_ref();
1121  for(; it != items.end(); ++it) {
1122  self_callable.add("a", res);
1123  self_callable.add("b", *it);
1124  res = args().back()->evaluate(formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)),fdb);
1125  }
1126  return res;
1127  }
1128 };
1129 
1130 class sum_function : public function_expression {
1131 public:
1132  explicit sum_function(const args_list& args)
1133  : function_expression("sum", args, 1, 2)
1134  {}
1135 private:
1136  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1137  variant res(0);
1138  const variant items = args()[0]->evaluate(variables,fdb);
1139  if (items.num_elements() > 0)
1140  {
1141  if (items[0].is_list() )
1142  {
1143  std::vector<variant> tmp;
1144  res = variant(&tmp);
1145  if(args().size() >= 2) {
1146  res = args()[1]->evaluate(variables,fdb);
1147  if(!res.is_list())
1148  return variant();
1149  }
1150  } else if( items[0].is_map() )
1151  {
1152  std::map<variant,variant> tmp;
1153  res = variant(&tmp);
1154  if(args().size() >= 2) {
1155  res = args()[1]->evaluate(variables,fdb);
1156  if(!res.is_map())
1157  return variant();
1158  }
1159  } else
1160  {
1161  if(args().size() >= 2) {
1162  res = args()[1]->evaluate(variables,fdb);
1163  }
1164  }
1165  }
1166 
1167  for(size_t n = 0; n != items.num_elements(); ++n) {
1168  res = res + items[n];
1169  }
1170 
1171  return res;
1172  }
1173 };
1174 
1175 class head_function : public function_expression {
1176 public:
1177  explicit head_function(const args_list& args)
1178  : function_expression("head", args, 1, 2)
1179  {}
1180 private:
1181  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1182  const variant items = args()[0]->evaluate(variables,fdb);
1183  variant_iterator it = items.begin();
1184  if(it == items.end()) {
1185  return variant();
1186  }
1187  if(args().size() == 1) {
1188  return *it;
1189  }
1190  const int n = items.num_elements(), req = args()[1]->evaluate(variables,fdb).as_int();
1191  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1192  variant_iterator end = it;
1193  std::advance(end, count);
1194  std::vector<variant> res;
1195  std::copy(it, end, std::back_inserter(res));
1196  return variant(&res);
1197  }
1198 };
1199 
1200 class tail_function : public function_expression {
1201 public:
1202  explicit tail_function(const args_list& args)
1203  : function_expression("tail", args, 1, 2)
1204  {}
1205 private:
1206  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1207  const variant items = args()[0]->evaluate(variables,fdb);
1208  variant_iterator it = items.end();
1209  if(it == items.begin()) {
1210  return variant();
1211  }
1212  if(args().size() == 1) {
1213  return *--it;
1214  }
1215  const int n = items.num_elements(), req = args()[1]->evaluate(variables,fdb).as_int();
1216  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1217  std::advance(it, -count);
1218  std::vector<variant> res;
1219  std::copy(it, items.end(), std::back_inserter(res));
1220  return variant(&res);
1221  }
1222 };
1223 
1224 class size_function : public function_expression {
1225 public:
1226  explicit size_function(const args_list& args)
1227  : function_expression("size", args, 1, 1)
1228  {}
1229 private:
1230  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1231  const variant items = args()[0]->evaluate(variables,fdb);
1232  return variant(static_cast<int>(items.num_elements()));
1233  }
1234 };
1235 
1236 class null_function : public function_expression {
1237 public:
1238  explicit null_function(const args_list& args)
1239  : function_expression("null", args, 0, -1)
1240  {}
1241 private:
1242  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1243  if( args().size() != 0 ) {
1244  for( size_t i = 0; i < args().size() ; ++i)
1245  args()[i]->evaluate(variables,fdb);
1246  }
1247 
1248  return variant();
1249  }
1250 };
1251 
1252 
1253 class ceil_function : public function_expression {
1254 public:
1255  explicit ceil_function(const args_list& args)
1256  : function_expression("ceil", args, 1, 1)
1257  {}
1258 private:
1259  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1260  variant decimal = args()[0]->evaluate(variables,fdb);
1261 
1262  int d = decimal.as_decimal();
1263 
1264  if( (d>=0) && (d%1000 != 0) ) {
1265  d/=1000;
1266  return variant( ++d );
1267  } else {
1268  d/=1000;
1269  return variant( d );
1270  }
1271  }
1272 };
1273 
1274 class round_function : public function_expression {
1275 public:
1276  explicit round_function(const args_list& args)
1277  : function_expression("round", args, 1, 1)
1278  {}
1279 private:
1280  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1281  variant decimal = args()[0]->evaluate(variables,fdb);
1282 
1283  int d = decimal.as_decimal();
1284 
1285  int f = d%1000;
1286 
1287  if( f >= 500 ) {
1288  d/=1000;
1289  return variant( ++d );
1290  } else if( f <= -500 ) {
1291  d/=1000;
1292  return variant( --d );
1293  } else {
1294  d/=1000;
1295  return variant( d );
1296  }
1297  }
1298 };
1299 
1300 class floor_function : public function_expression {
1301 public:
1302  explicit floor_function(const args_list& args)
1303  : function_expression("floor", args, 1, 1)
1304  {}
1305 private:
1306  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1307  variant decimal = args()[0]->evaluate(variables,fdb);
1308 
1309  int d = decimal.as_decimal();
1310 
1311  if( (d<0) && (d%1000 != 0) ) {
1312  d/=1000;
1313  return variant( --d );
1314  } else {
1315  d/=1000;
1316  return variant( d );
1317  }
1318  }
1319 };
1320 
1321 class trunc_function : public function_expression {
1322 public:
1323  explicit trunc_function(const args_list& args)
1324  : function_expression("trunc", args, 1, 1)
1325  {}
1326 private:
1327  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1328  variant decimal = args()[0]->evaluate(variables,fdb);
1329 
1330  int d = decimal.as_int();
1331 
1332  return variant( d );
1333  }
1334 };
1335 
1336 class frac_function : public function_expression {
1337 public:
1338  explicit frac_function(const args_list& args)
1339  : function_expression("frac", args, 1, 1)
1340  {}
1341 private:
1342  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1343  variant decimal = args()[0]->evaluate(variables,fdb);
1344 
1345  int d = decimal.as_decimal();
1346 
1347  d%=1000;
1348  return variant( d, variant::DECIMAL_VARIANT );
1349  }
1350 };
1351 
1352 class sgn_function : public function_expression {
1353 public:
1354  explicit sgn_function(const args_list& args)
1355  : function_expression("sgn", args, 1, 1)
1356  {}
1357 private:
1358  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1359  variant decimal = args()[0]->evaluate(variables,fdb);
1360 
1361  int d = decimal.as_decimal();
1362 
1363  if( d != 0 ) {
1364  d = d>0 ? 1 : -1;
1365  }
1366 
1367  return variant( d );
1368  }
1369 };
1370 
1371 class as_decimal_function : public function_expression {
1372 public:
1373  explicit as_decimal_function(const args_list& args)
1374  : function_expression("as_decimal", args, 1, 1)
1375  {}
1376 private:
1377  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1378  variant decimal = args()[0]->evaluate(variables,fdb);
1379 
1380  int d = decimal.as_decimal();
1381 
1382  return variant( d , variant::DECIMAL_VARIANT );
1383  }
1384 };
1385 
1386 
1387 class refcount_function : public function_expression {
1388 public:
1389  explicit refcount_function(const args_list& args)
1390  : function_expression("refcount", args, 1, 1)
1391  {}
1392 private:
1393  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1394  return variant(args()[0]->evaluate(variables,fdb).refcount());
1395  }
1396 };
1397 
1398 class loc_function : public function_expression {
1399 public:
1400  explicit loc_function(const args_list& args)
1401  : function_expression("loc", args, 2, 2)
1402  {}
1403 private:
1404  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1406  args()[0]->evaluate(variables,add_debug_info(fdb,0,"loc:x")).as_int()-1,
1407  args()[1]->evaluate(variables,add_debug_info(fdb,1,"loc:y")).as_int()-1)));
1408  }
1409 };
1410 
1411 class pair_function : public function_expression {
1412 public:
1413  explicit pair_function(const args_list& args)
1414  : function_expression("pair", args, 2, 2)
1415  {}
1416 private:
1417  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1418  return variant(new key_value_pair(
1419  args()[0]->evaluate(variables,add_debug_info(fdb,0,"pair:key")),
1420  args()[1]->evaluate(variables,add_debug_info(fdb,1,"pair_value"))
1421  ));
1422  }
1423 };
1424 
1425 class distance_between_function : public function_expression {
1426 public:
1427  explicit distance_between_function(const args_list& args)
1428  : function_expression("distance_between", args, 2, 2)
1429  {}
1430 
1431 private:
1432  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1433  const map_location loc1 = convert_variant<location_callable>(args()[0]->evaluate(variables,add_debug_info(fdb,0,"distance_between:location_A")))->loc();
1434  const map_location loc2 = convert_variant<location_callable>(args()[1]->evaluate(variables,add_debug_info(fdb,1,"distance_between:location_B")))->loc();
1435  return variant(distance_between(loc1, loc2));
1436  }
1437 };
1438 
1439 
1440 class type_function : public function_expression {
1441 public:
1442  explicit type_function(const args_list& args)
1443  : function_expression("type", args, 1, 1)
1444  {}
1445 private:
1446  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
1447  const variant& v = args()[0]->evaluate(variables, fdb);
1448  return variant(v.type_string());
1449  }
1450 };
1451 
1452 }
1453 
1454 variant key_value_pair::get_value(const std::string& key) const
1455 {
1456  if(key == "key")
1457  {
1458  return key_;
1459  } else
1460  if(key == "value")
1461  {
1462  return value_;
1463  } else
1464  return variant();
1465 }
1466 
1467 void key_value_pair::get_inputs(std::vector<game_logic::formula_input>* inputs) const {
1468  inputs->push_back(game_logic::formula_input("key", game_logic::FORMULA_READ_ONLY));
1469  inputs->push_back(game_logic::formula_input("value", game_logic::FORMULA_READ_ONLY));
1470 }
1471 
1472 
1473 void key_value_pair::serialize_to_string(std::string& str) const {
1474  str += "pair(";
1475  key_.serialize_to_string(str);
1476  str += ",";
1477  value_.serialize_to_string(str);
1478  str += ")";
1479 }
1480 
1481 formula_function_expression::formula_function_expression(const std::string& name, const args_list& args, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& arg_names)
1482  : function_expression(name, args, arg_names.size(), arg_names.size()),
1483  formula_(formula), precondition_(precondition), arg_names_(arg_names), star_arg_(-1)
1484 {
1485  for(size_t n = 0; n != arg_names_.size(); ++n) {
1486  if(arg_names_.empty() == false && arg_names_[n][arg_names_[n].size()-1] == '*') {
1487  arg_names_[n].resize(arg_names_[n].size()-1);
1488  star_arg_ = n;
1489  break;
1490  }
1491  }
1492 }
1493 
1495 {
1496  static std::string indent;
1497  indent += " ";
1498  DBG_NG << indent << "executing '" << formula_->str() << "'\n";
1499  const int begin_time = SDL_GetTicks();
1500  map_formula_callable callable;
1501  for(size_t n = 0; n != arg_names_.size(); ++n) {
1502  variant var = args()[n]->evaluate(variables,fdb);
1503  callable.add(arg_names_[n], var);
1504  if(static_cast<int>(n) == star_arg_) {
1505  callable.set_fallback(var.as_callable());
1506  }
1507  }
1508 
1509  if(precondition_) {
1510  if(!precondition_->evaluate(callable,fdb).as_bool()) {
1511  DBG_NG << "FAILED function precondition for function '" << formula_->str() << "' with arguments: ";
1512  for(size_t n = 0; n != arg_names_.size(); ++n) {
1513  DBG_NG << " arg " << (n+1) << ": " << args()[n]->evaluate(variables,fdb).to_debug_string() << "\n";
1514  }
1515  }
1516  }
1517 
1518  variant res = formula_->evaluate(callable,fdb);
1519  const int taken = SDL_GetTicks() - begin_time;
1520  DBG_NG << indent << "returning: " << taken << "\n";
1521  indent.resize(indent.size() - 2);
1522 
1523  return res;
1524 }
1525 
1527 {
1529 }
1530 
1532 {
1533  custom_formulas_[name] = fcn;
1534 }
1535 
1536 expression_ptr function_symbol_table::create_function(const std::string& fn, const std::vector<expression_ptr>& args) const
1537 {
1538  const functions_map::const_iterator i = custom_formulas_.find(fn);
1539  if(i != custom_formulas_.end()) {
1540  return i->second->generate_function_expression(args);
1541  }
1542 
1543  return expression_ptr();
1544 }
1545 
1546 std::vector<std::string> function_symbol_table::get_function_names() const
1547 {
1548  std::vector<std::string> res;
1549  for(functions_map::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); ++iter ) {
1550  res.push_back((*iter).first);
1551  }
1552  return res;
1553 }
1554 
1555 namespace {
1556 
1557 function_symbol_table& get_functions_map() {
1558  static function_symbol_table functions_table;
1559 
1560  if(functions_table.empty()) {
1561 #define FUNCTION(name) functions_table.add_function(#name, \
1562  formula_function_ptr(new builtin_formula_function<name##_function>(#name)))
1563  FUNCTION(debug);
1564  FUNCTION(dir);
1565  FUNCTION(if);
1566  FUNCTION(switch);
1567  FUNCTION(abs);
1568  FUNCTION(min);
1569  FUNCTION(max);
1570  FUNCTION(choose);
1571  FUNCTION(debug_float);
1572  FUNCTION(debug_print);
1573  FUNCTION(debug_profile);
1574  FUNCTION(wave);
1575  FUNCTION(sort);
1576  FUNCTION(contains_string);
1577  FUNCTION(find_string);
1578  FUNCTION(reverse);
1579  FUNCTION(filter);
1580  FUNCTION(find);
1581  FUNCTION(map);
1582  FUNCTION(zip);
1583  FUNCTION(take_while);
1584  FUNCTION(reduce);
1585  FUNCTION(sum);
1586  FUNCTION(head);
1587  FUNCTION(tail);
1588  FUNCTION(size);
1589  FUNCTION(null);
1590  FUNCTION(ceil);
1591  FUNCTION(floor);
1592  FUNCTION(trunc);
1593  FUNCTION(frac);
1594  FUNCTION(sgn);
1595  FUNCTION(round);
1596  FUNCTION(as_decimal);
1597  FUNCTION(refcount);
1598  FUNCTION(pair);
1599  FUNCTION(loc);
1601  FUNCTION(index_of);
1602  FUNCTION(keys);
1603  FUNCTION(values);
1604  FUNCTION(tolist);
1605  FUNCTION(tomap);
1606  FUNCTION(substring);
1607  FUNCTION(replace);
1608  FUNCTION(length);
1609  FUNCTION(concatenate);
1610  FUNCTION(sin);
1611  FUNCTION(cos);
1612  FUNCTION(tan);
1613  FUNCTION(asin);
1614  FUNCTION(acos);
1615  FUNCTION(atan);
1616  FUNCTION(sqrt);
1617  FUNCTION(cbrt);
1618  FUNCTION(root);
1619  FUNCTION(log);
1620  FUNCTION(exp);
1621  FUNCTION(pi);
1622  FUNCTION(hypot);
1623  FUNCTION(type);
1624 #undef FUNCTION
1625  }
1626 
1627  return functions_table;
1628 }
1629 
1630 }
1631 
1633  const std::vector<expression_ptr>& args,
1634  const function_symbol_table* symbols)
1635 {
1636  if(symbols) {
1637  expression_ptr res(symbols->create_function(fn, args));
1638  if(res) {
1639  return res;
1640  }
1641  }
1642 
1643  expression_ptr res(get_functions_map().create_function(fn, args));
1644  if(!res) {
1645  throw formula_error("Unknown function: " + fn, "", "", 0);
1646  }
1647 
1648  return res;
1649 }
1650 
1651 std::vector<std::string> builtin_function_names()
1652 {
1653  return get_functions_map().get_function_names();
1654 }
1655 
1656 }
size_t num_elements() const
Definition: variant.cpp:526
variant execute(const formula_callable &variables, formula_debugger *fdb) const
Definition: function.cpp:1494
static lg::log_domain log_engine("engine")
SDL_Color create_color(const unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
Definition: utils.cpp:89
void add_function(const std::string &name, formula_function_ptr fcn)
Definition: function.cpp:1531
int pos
Definition: formula.cpp:800
variant b_
Definition: function.cpp:808
std::vector< std::string > args_
Definition: function.hpp:112
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
#define DBG_NG
Definition: function.cpp:34
Formula AI debugger.
#define LOG_SF
Definition: function.cpp:36
GLenum GLenum GLenum input
Definition: glew.h:10668
const game_logic::formula_callable * as_callable() const
Definition: variant.hpp:101
void float_label(const map_location &loc, const std::string &text, const SDL_Color &color)
Function to float a label above a tile.
static lg::log_domain log_scripting_formula("scripting/formula")
GLuint const GLfloat * val
Definition: glew.h:2614
expression_ptr create_function(const std::string &fn, const std::vector< expression_ptr > &args, const function_symbol_table *symbols)
Definition: function.cpp:1632
STL namespace.
variant_iterator end() const
Definition: variant.cpp:500
bool is_decimal() const
Definition: variant.hpp:82
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
const std::vector< std::string > items
bool as_bool() const
Definition: variant.cpp:580
#define d
std::vector< std::string > get_function_names() const
Definition: function.cpp:1546
bool is_null() const
Definition: variant.hpp:80
expression_ptr key_
Definition: formula.cpp:435
GLboolean GLenum GLenum GLvoid * values
Definition: glew.h:3799
GLuint GLsizei GLsizei * length
Definition: glew.h:1793
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
GLuint GLenum GLenum transform
Definition: glew.h:11418
GLintptr offset
Definition: glew.h:1650
std::vector< std::string > builtin_function_names()
Definition: function.cpp:1651
GLuint GLuint end
Definition: glew.h:1221
GLuint64EXT * result
Definition: glew.h:10727
bool is_list() const
Definition: variant.hpp:92
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.hpp:357
int as_int() const
Definition: variant.cpp:558
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
GLuint start
Definition: glew.h:1221
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
std::string string_cast() const
Definition: variant.cpp:1165
GLuint num
Definition: glew.h:2552
Iterator class for the variant.
Definition: variant.hpp:188
variant get_keys() const
Definition: variant.cpp:468
static int indent
Definition: log.cpp:45
GLuint GLuint GLsizei count
Definition: glew.h:1221
boost::shared_ptr< function_expression > function_expression_ptr
Definition: function.hpp:98
std::vector< std::string > arg_names_
Definition: function.hpp:94
Encapsulates the map of the game.
Definition: location.hpp:38
GLuint res
Definition: glew.h:9258
static const char * output
Definition: luac.cpp:31
variant_iterator begin() const
Definition: variant.cpp:490
boost::shared_ptr< formula_expression > expression_ptr
Definition: formula.hpp:26
int as_decimal() const
Definition: variant.cpp:565
bool is_map() const
Definition: variant.hpp:83
const args_list & args() const
Definition: function.hpp:68
static void expr(LexState *ls, expdesc *v)
Definition: lparser.cpp:1066
function_expression_ptr generate_function_expression(const std::vector< expression_ptr > &args) const
Definition: function.cpp:1526
size_t i
Definition: function.cpp:1057
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
map_formula_callable & add(const std::string &key, const variant &value)
Definition: formula.cpp:41
const_formula_ptr precondition_
Definition: function.hpp:111
#define debug(x)
static int sort(lua_State *L)
Definition: ltablib.cpp:246
variant a_
Definition: function.cpp:808
std::string replace(std::string str, const std::string &src, const std::string &dst)
Replace all instances of src in str with dst.
GLuint const GLchar * name
Definition: glew.h:1782
const formula_callable * fallback_
Definition: function.cpp:807
GLsizeiptr size
Definition: glew.h:1649
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:3448
display_chat_manager & get_chat_manager()
std::string to_debug_string(std::vector< const game_logic::formula_callable * > *seen=nullptr, bool verbose=false) const
Definition: variant.cpp:1229
GLclampd n
Definition: glew.h:5903
const GLdouble * m
Definition: glew.h:6968
bool find(E event, F functor)
Tests whether an event handler is available.
expression_ptr create_function(const std::string &fn, const std::vector< expression_ptr > &args) const
Definition: function.cpp:1536
variant get_values() const
Definition: variant.cpp:479
GLdouble angle
Definition: glew.h:6979
const std::vector< variant > & as_list() const
Definition: variant.cpp:610
Standard logging facilities (interface).
#define FUNCTION(name)
bool is_string() const
Definition: variant.hpp:79
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
void add_chat_message(const time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
GLdouble s
Definition: glew.h:1358
GLsizei const GLcharARB ** string
Definition: glew.h:4503
expression_ptr expr_
Definition: function.cpp:806
std::string type_string() const
Definition: variant.cpp:339
static game_display * get_singleton()
bool is_int() const
Definition: variant.hpp:81
std::vector< expression_ptr > args_list
Definition: function.hpp:50
GLclampf f
Definition: glew.h:3024
void set_fallback(const formula_callable *fallback)
Definition: callable.hpp:159