The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
formula.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 by David White <dave.net>
3  Part of the Silver Tree Project
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 or later.
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY.
9 
10  See the COPYING file for more details.
11 */
12 #include "global.hpp"
13 
14 #include <boost/lexical_cast.hpp>
15 #include <iostream>
16 #include <set>
17 #include <sstream>
18 
19 #include "formula/callable.hpp"
20 #include "formula/function.hpp"
21 #include "random_new.hpp"
23 
24 namespace game_logic
25 {
26 
27 const char*const formula::id_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
28 
29 void formula_callable::set_value(const std::string& key, const variant& /*value*/)
30 {
31  std::cerr << "ERROR: cannot set key '" << key << "' on object" << std::endl;
32 }
33 
34 
36  formula_callable(false),
37  values_(),
38  fallback_(fallback)
39 {}
40 
42  const variant& value)
43 {
44  values_[key] = value;
45  return *this;
46 }
47 
49 {
50  std::map<std::string,variant>::const_iterator it = values_.find(key);
51  if(it != values_.end()) {
52  return it->second;
53  } else if(fallback_) {
54  return fallback_->query_value(key);
55  } else {
56  return variant();
57  }
58 }
59 
60 void map_formula_callable::get_inputs(std::vector<formula_input>* inputs) const
61 {
62  if(fallback_) {
63  fallback_->get_inputs(inputs);
64  }
65  for(std::map<std::string,variant>::const_iterator i = values_.begin(); i != values_.end(); ++i) {
66  inputs->push_back(formula_input(i->first, FORMULA_READ_WRITE));
67  }
68 }
69 
71 {
72  values_[key] = value;
73 }
74 
75 namespace {
76 
77 class function_list_expression : public formula_expression {
78 public:
79  explicit function_list_expression(function_symbol_table *symbols)
80  : symbols_(symbols)
81  {}
82 
83  virtual std::string str() const
84  {
85  return "{function_list_expression()}";
86  }
87 private:
88  variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
89  std::vector<variant> res;
90  std::vector<std::string> function_names = builtin_function_names();
91  std::vector<std::string> more_function_names = symbols_->get_function_names();
92  function_names.insert(function_names.end(), more_function_names.begin(), more_function_names.end());
93  for(size_t i = 0; i < function_names.size(); i++) {
94  res.push_back(variant(function_names[i]));
95  }
96  return variant(&res);
97  }
98 
99  function_symbol_table* symbols_;
100 };
101 
102 class list_expression : public formula_expression {
103 public:
104  explicit list_expression(const std::vector<expression_ptr>& items)
105  : items_(items)
106  {}
107 
108 private:
109  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
110  std::vector<variant> res;
111  res.reserve(items_.size());
112  for(std::vector<expression_ptr>::const_iterator i = items_.begin(); i != items_.end(); ++i) {
113  res.push_back((*i)->evaluate(variables,add_debug_info(fdb, 0, "[list element]")));
114  }
115 
116  return variant(&res);
117  }
118 
119  std::vector<expression_ptr> items_;
120 
121  std::string str() const
122  {
123  std::stringstream s;
124  s << '[';
125  bool first_item = true;
126  for(expression_ptr a : items_) {
127  if (!first_item) {
128  s << ',';
129  } else {
130  first_item = false;
131  }
132  s << a->str();
133  }
134  s << ']';
135  return s.str();
136  }
137 
138 
139 };
140 
141 class map_expression : public formula_expression {
142 public:
143  explicit map_expression(const std::vector<expression_ptr>& items)
144  : items_(items)
145  {}
146 
147  virtual std::string str() const
148  {
149  std::stringstream s;
150  s << " [";
151  for(std::vector<expression_ptr>::const_iterator i = items_.begin(); ( i != items_.end() ) && ( i+1 != items_.end() ) ; i+=2) {
152  if(i != items_.begin()) {
153  s << ", ";
154  }
155  s << (*i)->str();
156  s << " -> ";
157  s << (*(i+1))->str();
158  }
159  if(items_.empty()) {
160  s << "->";
161  }
162  s << " ]";
163  return s.str();
164  }
165 private:
166  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
167  std::map<variant,variant> res;
168  for(std::vector<expression_ptr>::const_iterator i = items_.begin(); ( i != items_.end() ) && ( i+1 != items_.end() ) ; i+=2) {
169  variant key = (*i)->evaluate(variables,add_debug_info(fdb, 0, "key ->"));
170  variant value = (*(i+1))->evaluate(variables,add_debug_info(fdb, 1, "-> value"));
171  res[ key ] = value;
172  }
173 
174  return variant(&res);
175  }
176 
177  std::vector<expression_ptr> items_;
178 };
179 
180 class unary_operator_expression : public formula_expression {
181 public:
182  unary_operator_expression(const std::string& op, expression_ptr arg) :
183  op_(),op_str_(op),
184  operand_(arg)
185  {
186  if(op == "not") {
187  op_ = NOT;
188  } else if(op == "-") {
189  op_ = SUB;
190  } else {
191  throw formula_error("Illegal unary operator: '" + op + "'" , "", "", 0);
192  }
193  }
194 
195  virtual std::string str() const {
196  std::stringstream s;
197  s << op_str_ << '('<< operand_->str() << ')';
198  return s.str();
199  }
200 
201 private:
202  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
203  const variant res = operand_->evaluate(variables,add_debug_info(fdb, 0, op_str_ + " unary"));
204  switch(op_) {
205  case NOT:
206  return res.as_bool() ? variant(0) : variant(1);
207  case SUB:
208  default:
209  return -res;
210  }
211  }
212  enum OP { NOT, SUB };
213  OP op_;
216 };
217 
218 class string_callable : public formula_callable {
220 public:
221  explicit string_callable(const variant& string) : string_(string)
222  {}
223 
224  void get_inputs(std::vector<formula_input>* inputs) const {
225  inputs->push_back(formula_input("size", FORMULA_READ_ONLY));
226  inputs->push_back(formula_input("empty", FORMULA_READ_ONLY));
227  inputs->push_back(formula_input("char", FORMULA_READ_ONLY));
228  inputs->push_back(formula_input("word", FORMULA_READ_ONLY));
229  inputs->push_back(formula_input("item", FORMULA_READ_ONLY));
230  }
231 
232  variant get_value(const std::string& key) const {
233  if(key == "size") {
234  return variant(string_.as_string().length());
235  } else if(key == "empty") {
236  return variant(string_.as_string().empty());
237  } else if(key == "char" || key == "chars") {
238  std::vector<variant> chars;
239  for(char c : string_.as_string()) {
240  chars.push_back(variant(std::string(1, c)));
241  }
242  return variant(&chars);
243  } else if(key == "word" || key == "words") {
244  std::vector<variant> words;
245  const std::string& str = string_.as_string();
246  size_t next_space = 0;
247  do {
248  size_t last_space = next_space;
249  next_space = str.find_first_of(" \t", next_space);
250  words.push_back(variant(str.substr(last_space, next_space - last_space)));
251  next_space = str.find_first_not_of(" \t", next_space);
252  } while(next_space != std::string::npos);
253  return variant(&words);
254  } else if(key == "item" || key == "items") {
255  std::vector<std::string> split = utils::parenthetical_split(string_.as_string(), ',');
256  std::vector<variant> items;
257  items.reserve(split.size());
258  for(const std::string s : split) {
259  items.push_back(variant(s));
260  }
261  return variant(&items);
262  } else {
263  return variant();
264  }
265  }
266 };
267 
268 class list_callable : public formula_callable {
270 public:
271  explicit list_callable(const variant& list) : list_(list)
272  {}
273 
274  void get_inputs(std::vector<formula_input>* inputs) const {
275  inputs->push_back(formula_input("size", FORMULA_READ_WRITE));
276  inputs->push_back(formula_input("empty", FORMULA_READ_WRITE));
277  inputs->push_back(formula_input("first", FORMULA_READ_WRITE));
278  inputs->push_back(formula_input("last", FORMULA_READ_WRITE));
279  }
280 
281  variant get_value(const std::string& key) const {
282  if(key == "size") {
283  return variant(list_.num_elements());
284  } else if(key == "empty") {
285  return variant(list_.num_elements() == 0);
286  } else if(key == "first") {
287  if(list_.num_elements() > 0) {
288  return list_[0];
289  } else {
290  return variant();
291  }
292  } else if(key == "last") {
293  if(list_.num_elements() > 0) {
294  return list_[list_.num_elements()-1];
295  } else {
296  return variant();
297  }
298  } else {
299  return variant();
300  }
301  }
302 
303 };
304 
305 class map_callable : public formula_callable {
307 public:
308  explicit map_callable(const variant& map) : map_(map)
309  {}
310 
311  void get_inputs(std::vector<formula_input>* inputs) const {
312  inputs->push_back(formula_input("size", FORMULA_READ_WRITE));
313  inputs->push_back(formula_input("empty", FORMULA_READ_WRITE));
314  for(variant_iterator iter = map_.begin(); iter != map_.end(); iter++) {
315  // variant_iterator does not implement operator->,
316  // and to do so is notrivial since it returns temporaries for maps.
317  const variant& key_variant = (*iter).get_member("key");
318  if(!key_variant.is_string()) {
319  continue;
320  }
321  std::string key = key_variant.as_string();
322  bool valid = true;
323  for(char c : key) {
324  if(!isalpha(c) && c != '_') {
325  valid = false;
326  break;
327  }
328  }
329  if(valid) {
330  inputs->push_back(formula_input(key, FORMULA_READ_ONLY));
331  }
332  }
333  }
334 
335  variant get_value(const std::string& key) const {
336  const variant key_variant(key);
337  if(map_.as_map().find(key_variant) != map_.as_map().end()) {
338  return map_[key_variant];
339  } else if(key == "size") {
340  return variant(map_.num_elements());
341  } else if(key == "empty") {
342  return variant(map_.num_elements() == 0);
343  } else {
344  return variant();
345  }
346  }
347 };
348 
349 class dot_callable : public formula_callable {
350 public:
351  dot_callable(const formula_callable &global,
352  const formula_callable& local)
353  : global_(global), local_(local) { }
354 private:
355  const formula_callable& global_, &local_;
356 
357  void get_inputs(std::vector<formula_input>* inputs) const {
358  return local_.get_inputs(inputs);
359  }
360 
361  variant get_value(const std::string& key) const {
362  variant v = local_.query_value(key);
363 
364  if ( v == variant() )
365  return global_.query_value(key);
366  else
367  return v;
368  }
369 };
370 
371 class dot_expression : public formula_expression {
372 public:
373  dot_expression(expression_ptr left, expression_ptr right)
374  : left_(left), right_(right)
375  {}
376  std::string str() const
377  {
378  std::stringstream s;
379  s << left_->str() << "." << right_->str();
380  return s.str();
381  }
382 private:
383  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
384  const variant left = left_->evaluate(variables,add_debug_info(fdb,0,"left ."));
385  if(!left.is_callable()) {
386  if(left.is_list()) {
387  list_callable list_call(left);
388  dot_callable callable(variables, list_call);
389  return right_->evaluate(callable,fdb);
390  }
391  if(left.is_map()) {
392  map_callable map_call(left);
393  dot_callable callable(variables, map_call);
394  return right_->evaluate(callable,fdb);
395  }
396  if(left.is_string()) {
397  string_callable string_call(left);
398  dot_callable callable(variables, string_call);
399  return right_->evaluate(callable,fdb);
400  }
401 
402  return left;
403  }
404 
405  dot_callable callable(variables, *left.as_callable());
406  return right_->evaluate(callable,add_debug_info(fdb,1,". right"));
407  }
408 
410 };
411 
412 class square_bracket_expression : public formula_expression {
413 public:
414  square_bracket_expression(expression_ptr left, expression_ptr key)
415  : left_(left), key_(key)
416  {}
417 
418  std::string str() const
419  {
420  std::stringstream s;
421  s << left_->str() << '[' << key_->str() << ']';
422  return s.str();
423  }
424 private:
425  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
426  const variant left = left_->evaluate(variables,add_debug_info(fdb,0,"base[]"));
427  const variant key = key_->evaluate(variables,add_debug_info(fdb,1,"[index]"));
428  if(left.is_list() || left.is_map()) {
429  return left[ key ];
430  } else {
431  return variant();
432  }
433  }
434 
436 };
437 
438 class operator_expression : public formula_expression {
439 public:
440  operator_expression(const std::string& op, expression_ptr left,
442  : op_(OP(op[0])), op_str_(op), left_(left), right_(right)
443  {
444  if(op == ">=") {
445  op_ = GTE;
446  } else if(op == "<=") {
447  op_ = LTE;
448  } else if(op == "!=") {
449  op_ = NEQ;
450  } else if(op == "and") {
451  op_ = AND;
452  } else if(op == "or") {
453  op_ = OR;
454  } else if(op == ".+") {
455  op_ = ADDL;
456  } else if(op == ".-") {
457  op_ = SUBL;
458  } else if(op == ".*") {
459  op_ = MULL;
460  } else if(op == "./") {
461  op_ = DIVL;
462  } else if(op == "..") {
463  op_ = OP_CAT;
464  } else if(op == "in") {
465  op_ = OP_IN;
466  }
467  }
468 
469  std::string str() const
470  {
471  std::stringstream s;
472  s << '(' << left_->str() << op_str_ << right_->str() << ')';
473  return s.str();
474  }
475 private:
476  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
477  const variant left = left_->evaluate(variables,add_debug_info(fdb,0,"left " + op_str_));
478  const variant right = right_->evaluate(variables,add_debug_info(fdb,1,op_str_ + " right"));
479  switch(op_) {
480  case AND:
481  return left.as_bool() == false ? left : right;
482  case OR:
483  return left.as_bool() ? left : right;
484  case ADD:
485  return left + right;
486  case SUB:
487  return left - right;
488  case MUL:
489  return left * right;
490  case DIV:
491  return left / right;
492  case POW:
493  return left ^ right;
494  case ADDL:
495  return left.list_elements_add(right);
496  case SUBL:
497  return left.list_elements_sub(right);
498  case MULL:
499  return left.list_elements_mul(right);
500  case DIVL:
501  return left.list_elements_div(right);
502  case OP_IN:
503  return variant(right.contains(left));
504  case OP_CAT:
505  return left.concatenate(right);
506  case EQ:
507  return left == right ? variant(1) : variant(0);
508  case NEQ:
509  return left != right ? variant(1) : variant(0);
510  case LTE:
511  return left <= right ? variant(1) : variant(0);
512  case GTE:
513  return left >= right ? variant(1) : variant(0);
514  case LT:
515  return left < right ? variant(1) : variant(0);
516  case GT:
517  return left > right ? variant(1) : variant(0);
518  case MOD:
519  return left % right;
520  case RAN:
521  return left.build_range(right);
522  case DICE:
523  return variant(dice_roll(left.as_int(), right.as_int()));
524  default:
525  std::cerr << "ERROR: Unimplemented operator!" << std::endl;
526  return variant();
527  }
528  }
529 
530  static int dice_roll(int num_rolls, int faces) {
531  int res = 0;
532  while(faces > 0 && num_rolls-- > 0) {
534  res += (random_new::generator->next_random() % faces) + 1;
535  } else {
536  res += (rand() % faces) + 1;
537  }
538  }
539  return res;
540  }
541 
542  //In some cases a IN or CAT macros are defined.
543  enum OP { AND, OR, NEQ, LTE, GTE, OP_CAT, OP_IN, GT='>', LT='<', EQ='=', RAN='~',
544  ADD='+', SUB='-', MUL='*', DIV='/', ADDL, SUBL, MULL, DIVL, DICE='d', POW='^', MOD='%' };
545 
546  OP op_;
549 };
550 
551 typedef std::map<std::string,expression_ptr> expr_table;
552 typedef boost::shared_ptr<expr_table> expr_table_ptr;
553 typedef std::map<std::string, variant> exp_table_evaluated;
554 
555 class where_variables: public formula_callable {
556 public:
557  where_variables(const formula_callable &base,
558  expr_table_ptr table, formula_debugger* fdb )
559  : formula_callable(false)
560  , base_(base)
561  , table_(table)
562  , evaluated_table_()
563  , debugger_(fdb)
564  {
565  }
566 
567 private:
568  const formula_callable& base_;
569  expr_table_ptr table_;
570  mutable exp_table_evaluated evaluated_table_;
571  formula_debugger* debugger_;
572 
573  void get_inputs(std::vector<formula_input>* inputs) const {
574  for(expr_table::const_iterator i = table_->begin(); i != table_->end(); ++i) {
575  inputs->push_back(formula_input(i->first, FORMULA_READ_ONLY));
576  }
577  }
578 
579  variant get_value(const std::string& key) const {
580  expr_table::iterator i = table_->find(key);
581  if(i != table_->end()) {
582  exp_table_evaluated::const_iterator ev = evaluated_table_.find(key);
583  if( ev != evaluated_table_.end())
584  return ev->second;
585 
586  variant v = i->second->evaluate(base_, add_debug_info(debugger_, 0, "where[" + key + "]"));
587  evaluated_table_[key] = v;
588  return v;
589  }
590  return base_.query_value(key);
591  }
592 };
593 
594 class where_expression: public formula_expression {
595 public:
596  explicit where_expression(expression_ptr body,
597  expr_table_ptr clauses)
598  : body_(body), clauses_(clauses)
599  {}
600 
601  std::string str() const
602  {
603  std::stringstream s;
604  s << "{where:(";
605  s << body_->str();
606  for(const expr_table::value_type &a : *clauses_) {
607  s << ", [" << a.first << "] -> ["<< a.second->str()<<"]";
608  }
609  s << ")}";
610  return s.str();
611  }
612 
613 private:
615  expr_table_ptr clauses_;
616 
617  variant execute(const formula_callable& variables,formula_debugger *fdb) const {
618  where_variables wrapped_variables(variables, clauses_, fdb);
619  return body_->evaluate(wrapped_variables,add_debug_info(fdb, 0, "... where"));
620  }
621 };
622 
623 
624 class identifier_expression : public formula_expression {
625 public:
626  explicit identifier_expression(const std::string& id) : id_(id)
627  {}
628  std::string str() const
629  {
630  return id_;
631  }
632 private:
633  variant execute(const formula_callable& variables, formula_debugger * /*fdb*/) const {
634  return variables.query_value(id_);
635  }
637 };
638 
639 class null_expression : public formula_expression {
640 public:
641  explicit null_expression() {}
642  std::string str() const {
643  return "";
644  }
645 private:
646  variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
647  return variant();
648  }
649 };
650 
651 
652 class integer_expression : public formula_expression {
653 public:
654  explicit integer_expression(int i) : i_(i)
655  {}
656  std::string str() const
657  {
658  std::stringstream s;
659  s << i_;
660  return s.str();
661  }
662 private:
663  variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
664  return variant(i_);
665  }
666 
667  int i_;
668 };
669 
670 class decimal_expression : public formula_expression {
671 public:
672  explicit decimal_expression(int i, int f) : i_(i), f_(f)
673  {}
674 
675  std::string str() const
676  {
677  std::stringstream s;
678  s << i_ << '.';
679  s.width(3);
680  s.fill('0');
681  s << f_;
682  return s.str();
683  }
684 private:
685  variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
686  return variant(i_ * 1000 + f_, variant::DECIMAL_VARIANT );
687  }
688 
689  int i_, f_;
690 };
691 
692 class string_expression : public formula_expression {
693 public:
694  explicit string_expression(std::string str) :
695  str_(),
696  subs_()
697  {
698  std::string::iterator i = str.begin();
699  while((i = std::find(i, str.end(), '[')) != str.end()) {
700  int bracket_depth = 0;
701  std::string::iterator j = i + 1;
702  while(j != str.end() && (bracket_depth > 0 || *j != ']')) {
703  if(*j == '[') {
704  bracket_depth++;
705  } else if(*j == ']' && bracket_depth > 0) {
706  bracket_depth--;
707  }
708  ++j;
709  }
710  if(j == str.end()) {
711  break;
712  }
713 
714  const std::string formula_str(i+1, j);
715  const int pos = i - str.begin();
716  if(j - i == 2 && (i[1] == '(' || i[1] == '\'' || i[1] == ')')) {
717  // Bracket contained nothing but a quote or parenthesis.
718  // This means it was intended as a literal quote or square bracket.
719  i = str.erase(i);
720  if(*i == '(') *i = '[';
721  else if(*i == ')') *i = ']';
722  i = str.erase(i + 1);
723  continue;
724  } else {
725  i = str.erase(i, j+1);
726  }
727 
728  substitution sub;
729  sub.pos = pos;
730  try {
731  sub.calculation.reset(new formula(formula_str));
732  } catch(formula_error& e) {
733  e.filename += " - string substitution";
734  throw e;
735  }
736  subs_.push_back(sub);
737  }
738 
739  std::reverse(subs_.begin(), subs_.end());
740 
741  str_ = variant(str);
742  }
743 
744  std::string str() const
745  {
746  std::string res = str_.as_string();
747  int j = res.size() - 1;
748  for(size_t i = 0; i < subs_.size(); ++i) {
749  const substitution& sub = subs_[i];
750  for(;j >= sub.pos && j >= 0;j--) {
751  if(res[j] == '\'') {
752  res.replace(j, 1, "[']");
753  } else if(res[j] == '[') {
754  res.replace(j, 1, "[(]");
755  } else if(res[j] == ']') {
756  res.replace(j, 1, "[)]");
757  }
758  }
759  const std::string str = "[" + sub.calculation->str() + "]";
760  res.insert(sub.pos, str);
761  }
762  for(;j >= 0;j--) {
763  if(res[j] == '\'') {
764  res.replace(j, 1, "[']");
765  } else if(res[j] == '[') {
766  res.replace(j, 1, "[(]");
767  } else if(res[j] == ']') {
768  res.replace(j, 1, "[)]");
769  }
770  }
771 
772  return "'" + res + "'";
773  }
774 private:
775  variant execute(const formula_callable& variables, formula_debugger *fdb) const {
776  if(subs_.empty()) {
777  return str_;
778  } else {
779  std::string res = str_.as_string();
780  for(size_t i=0; i < subs_.size(); ++i) {
781  const int j = subs_.size() - i - 1;
782  const substitution& sub = subs_[i];
783  add_debug_info(fdb, j, "[string subst]");
784  const std::string str = sub.calculation->evaluate(variables,fdb).string_cast();
785  res.insert(sub.pos, str);
786  }
787 
788  return variant(res);
789  }
790  }
791 
792  struct substitution {
793 
794  substitution() :
795  pos(0),
796  calculation()
797  {
798  }
799 
800  int pos;
802  };
803 
804  variant str_;
805  std::vector<substitution> subs_;
806 };
807 
808 using namespace formula_tokenizer;
809 int operator_precedence(const token& t)
810 {
811  static std::map<std::string,int> precedence_map;
812  if(precedence_map.empty()) {
813  int n = 0;
814  precedence_map["not"] = ++n;
815  precedence_map["where"] = ++n;
816  precedence_map["or"] = ++n;
817  precedence_map["and"] = ++n;
818  precedence_map["="] = ++n;
819  precedence_map["!="] = n;
820  precedence_map["<"] = n;
821  precedence_map[">"] = n;
822  precedence_map["<="] = n;
823  precedence_map[">="] = n;
824  precedence_map["in"] = n;
825  precedence_map["~"] = ++n;
826  precedence_map["+"] = ++n;
827  precedence_map["-"] = n;
828  precedence_map[".."] = n;
829  precedence_map["*"] = ++n;
830  precedence_map["/"] = n;
831  precedence_map["%"] = ++n;
832  precedence_map["^"] = ++n;
833  precedence_map["d"] = ++n;
834  precedence_map["."] = ++n;
835  }
836 
837  assert(precedence_map.count(std::string(t.begin,t.end)));
838  return precedence_map[std::string(t.begin,t.end)];
839 }
840 
841 expression_ptr parse_expression(const token* i1, const token* i2, function_symbol_table* symbols);
842 
843 
844 //function used when creating error reports, parses all tokens passed to parse_expression, thus there are no EOL or whitespaces
845 std::string tokens_to_string(const token* i1, const token* i2)
846 {
847  std::ostringstream expr;
848  while(i1 != i2) {
849  expr << std::string(i1->begin,i1->end) << " ";
850  ++i1;
851  }
852  return expr.str();
853 }
854 
855 void parse_function_args(const token* &i1, const token* i2,
856  std::vector<std::string>* res)
857 {
858  const token* begin = i1, *end = i2; //these are used for error reporting
859 
860  if(i1->type == TOKEN_LPARENS) {
861  ++i1;
862  } else {
863  throw formula_error("Invalid function definition", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
864  }
865 
866  while((i1-> type != TOKEN_RPARENS) && (i1 != i2)) {
867  if(i1->type == TOKEN_IDENTIFIER) {
868  if(std::string((i1+1)->begin, (i1+1)->end) == "*") {
869  res->push_back(std::string(i1->begin, i1->end) + std::string("*"));
870  ++i1;
871  } else {
872  res->push_back(std::string(i1->begin, i1->end));
873  }
874  } else if (i1->type == TOKEN_COMMA) {
875  //do nothing
876  } else {
877  throw formula_error("Invalid function definition", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
878  }
879  ++i1;
880  }
881 
882  if(i1->type != TOKEN_RPARENS) {
883  throw formula_error("Invalid function definition", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
884  }
885  ++i1;
886 }
887 
888 void parse_args(const token* i1, const token* i2,
889  std::vector<expression_ptr>* res,
890  function_symbol_table* symbols)
891 {
892  int parens = 0;
893  const token* beg = i1;
894  while(i1 != i2) {
895  if(i1->type == TOKEN_LPARENS || i1->type == TOKEN_LSQUARE ) {
896  ++parens;
897  } else if(i1->type == TOKEN_RPARENS || i1->type == TOKEN_RSQUARE ) {
898  --parens;
899  } else if(i1->type == TOKEN_COMMA && !parens) {
900  res->push_back(parse_expression(beg,i1, symbols));
901  beg = i1+1;
902  }
903  ++i1;
904  }
905 
906  if(beg != i1) {
907  res->push_back(parse_expression(beg,i1, symbols));
908  }
909 }
910 
911 void parse_set_args(const token* i1, const token* i2,
912  std::vector<expression_ptr>* res,
913  function_symbol_table* symbols)
914 {
915  int parens = 0;
916  bool check_pointer = false;
917  const token* beg = i1;
918  const token* begin = i1, *end = i2; //these are used for error reporting
919  while(i1 != i2) {
920  if(i1->type == TOKEN_LPARENS || i1->type == TOKEN_LSQUARE) {
921  ++parens;
922  } else if(i1->type == TOKEN_RPARENS || i1->type == TOKEN_RSQUARE) {
923  --parens;
924  } else if( i1->type == TOKEN_POINTER && !parens ) {
925  if (!check_pointer) {
926  check_pointer = true;
927  res->push_back(parse_expression(beg,i1, symbols));
928  beg = i1+1;
929  } else {
930  throw formula_error("Too many '->' operators found", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
931  }
932  } else if( i1->type == TOKEN_COMMA && !parens ) {
933  if (check_pointer)
934  check_pointer = false;
935  else {
936  throw formula_error("Expected comma, but '->' found", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
937  }
938  res->push_back(parse_expression(beg,i1, symbols));
939  beg = i1+1;
940  }
941 
942  ++i1;
943  }
944 
945  if(beg != i1) {
946  res->push_back(parse_expression(beg,i1, symbols));
947  }
948 }
949 
950 void parse_where_clauses(const token* i1, const token * i2,
951  expr_table_ptr res, function_symbol_table* symbols) {
952  int parens = 0;
953  const token *original_i1_cached = i1;
954  const token *beg = i1;
955  const token* begin = i1, *end = i2; //these are used for error reporting
956  std::string var_name;
957  while(i1 != i2) {
958  if(i1->type == TOKEN_LPARENS) {
959  ++parens;
960  } else if(i1->type == TOKEN_RPARENS) {
961  --parens;
962  } else if(!parens) {
963  if(i1->type == TOKEN_COMMA) {
964  if(var_name.empty()) {
965  throw formula_error("There is 'where <expression>' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
966  }
967  (*res)[var_name] = parse_expression(beg,i1, symbols);
968  beg = i1+1;
969  var_name = "";
970  } else if(i1->type == TOKEN_OPERATOR) {
971  std::string op_name(i1->begin, i1->end);
972  if(op_name == "=") {
973  if(beg->type != TOKEN_IDENTIFIER) {
974  if(i1 == original_i1_cached) {
975  throw formula_error("There is 'where <expression' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
976  } else {
977  throw formula_error("There is 'where <expression>=<expression>' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
978  }
979  } else if(beg+1 != i1) {
980  throw formula_error("There is 'where name <expression>=<expression>' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
981  } else if(!var_name.empty()) {
982  throw formula_error("There is 'where name=name=<expression>' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
983  }
984  var_name.insert(var_name.end(), beg->begin, beg->end);
985  beg = i1+1;
986  }
987  }
988  }
989  ++i1;
990  }
991  if(beg != i1) {
992  if(var_name.empty()) {
993  throw formula_error("There is 'where <expression>' but 'where name=<expression>' was needed", tokens_to_string(begin,end-1), *i1->filename, i1->line_number);
994  }
995  (*res)[var_name] = parse_expression(beg,i1, symbols);
996  }
997 }
998 
999 expression_ptr parse_expression(const token* i1, const token* i2, function_symbol_table* symbols)
1000 {
1001  if(i1 == i2) {
1002  throw formula_error("Empty expression", "", *i1->filename, i1->line_number);
1003  }
1004 
1005  const token* begin = i1, *end = i2; //these are used for error reporting
1006 
1007  if(i1->type == TOKEN_KEYWORD &&
1008  (i1+1)->type == TOKEN_IDENTIFIER) {
1009  if(std::string(i1->begin, i1->end) == "def") {
1010  ++i1;
1011  const std::string formula_name = std::string(i1->begin, i1->end);
1012  std::vector<std::string> args;
1013  parse_function_args(++i1, i2, &args);
1014  const token* beg = i1;
1015  while((i1 != i2) && (i1->type != TOKEN_SEMICOLON)) {
1016  ++i1;
1017  }
1018  const std::string precond = "";
1019  if(symbols == nullptr) {
1020  throw formula_error("Function symbol table required but not present", "",*i1->filename, i1->line_number);
1021  }
1022  symbols->add_function(formula_name,
1023  formula_function_ptr(new user_formula_function(formula_name,
1024  const_formula_ptr(new formula(beg, i1, symbols)),
1025  formula::create_optional_formula(precond, symbols),
1026  args)));
1027  if((i1 == i2) || (i1 == (i2-1))) {
1028  return expression_ptr(new function_list_expression(symbols));
1029  }
1030  else {
1031  return parse_expression((i1+1), i2, symbols);
1032  }
1033  }
1034  }
1035 
1036  int parens = 0;
1037  const token* op = nullptr;
1038  bool operator_group = false;
1039  for(const token* i = i1; i != i2; ++i) {
1040  if(i->type == TOKEN_LPARENS || i->type == TOKEN_LSQUARE) {
1041  ++parens;
1042  } else if(i->type == TOKEN_RPARENS || i->type == TOKEN_RSQUARE) {
1043  --parens;
1044  } else if(parens == 0 && i->type == TOKEN_OPERATOR) {
1045  if( ( !operator_group ) && (op == nullptr || operator_precedence(*op) >=
1046  operator_precedence(*i)) ) {
1047  // Need special exception for exponentiation to be right-associative
1048  if(*i->begin != '^' || op == nullptr || *op->begin != '^')
1049  op = i;
1050  }
1051  operator_group = true;
1052  } else {
1053  operator_group = false;
1054  }
1055  }
1056 
1057  if(op == nullptr) {
1058  if(i1->type == TOKEN_LPARENS && (i2-1)->type == TOKEN_RPARENS) {
1059  return parse_expression(i1+1,i2-1,symbols);
1060  } else if( (i2-1)->type == TOKEN_RSQUARE) { //check if there is [ ] : either a list/map definition, or a operator
1061  // First, a special case for an empty map
1062  if(i2 - i1 == 3 && i1->type == TOKEN_LSQUARE && (i1+1)->type == TOKEN_POINTER) {
1063  return expression_ptr(new map_expression(std::vector<expression_ptr>()));
1064  }
1065  const token* tok = i2-2;
1066  int square_parens = 0;
1067  bool is_map = false;
1068  while ( (tok->type != TOKEN_LSQUARE || square_parens) && tok != i1) {
1069  if (tok->type == TOKEN_RSQUARE) {
1070  square_parens++;
1071  } else if(tok->type == TOKEN_LSQUARE) {
1072  square_parens--;
1073  } else if( (tok->type == TOKEN_POINTER) && !square_parens ) {
1074  is_map = true;
1075  }
1076  --tok;
1077  }
1078  if (tok->type == TOKEN_LSQUARE) {
1079  if (tok == i1) {
1080  //create a list or a map
1081  std::vector<expression_ptr> args;
1082 
1083  if ( is_map ) {
1084  parse_set_args(i1+1, i2-1, &args, symbols);
1085  return expression_ptr(new map_expression(args));
1086  } else {
1087  parse_args(i1+1,i2-1,&args,symbols);
1088  return expression_ptr(new list_expression(args));
1089  }
1090  } else {
1091  //execute operator [ ]
1092  try{
1093  return expression_ptr(new square_bracket_expression(
1094  parse_expression(i1,tok,symbols),
1095  parse_expression(tok+1,i2-1,symbols)));
1096  }
1097  catch (formula_error& e){
1098  throw formula_error( e.type, tokens_to_string(i1, i2-1), *i1->filename, i1->line_number );
1099  }
1100  }
1101  }
1102  } else if(i2 - i1 == 1) {
1103  if(i1->type == TOKEN_KEYWORD) {
1104  if(std::string(i1->begin,i1->end) == "functions") {
1105  return expression_ptr(new function_list_expression(symbols));
1106  }
1107  } else if(i1->type == TOKEN_IDENTIFIER) {
1108  return expression_ptr(new identifier_expression(
1109  std::string(i1->begin,i1->end)));
1110  } else if(i1->type == TOKEN_INTEGER) {
1111  int n = std::stoi(std::string(i1->begin,i1->end));
1112  return expression_ptr(new integer_expression(n));
1113  } else if(i1->type == TOKEN_DECIMAL) {
1114  iterator dot = i1->begin;
1115  while( *dot != '.' )
1116  ++dot;
1117 
1118  int n = std::stoi(std::string(i1->begin,dot));
1119 
1120  iterator end = i1->end;
1121 
1122  if( end - dot > 4)
1123  end = dot + 4;
1124 
1125  ++dot;
1126 
1127  int f = 0;
1128 
1129  int multiplicator = 100;
1130  while( dot != end) {
1131  f += (*dot - 48)*multiplicator;
1132  multiplicator /= 10;
1133  ++dot;
1134  }
1135 
1136  return expression_ptr(new decimal_expression(n, f));
1137  } else if(i1->type == TOKEN_STRING_LITERAL) {
1138  return expression_ptr(new string_expression(std::string(i1->begin+1,i1->end-1)));
1139  }
1140  } else if(i1->type == TOKEN_IDENTIFIER &&
1141  (i1+1)->type == TOKEN_LPARENS &&
1142  (i2-1)->type == TOKEN_RPARENS) {
1143  const token* begin = i1, *end = i2; //these are used for error reporting
1144  int nleft = 0, nright = 0;
1145  for(const token* i = i1; i != i2; ++i) {
1146  if(i->type == TOKEN_LPARENS) {
1147  ++nleft;
1148  } else if(i->type == TOKEN_RPARENS) {
1149  ++nright;
1150  }
1151  }
1152 
1153  if(nleft == nright) {
1154  std::vector<expression_ptr> args;
1155  parse_args(i1+2,i2-1,&args,symbols);
1156  try{
1157  return create_function(std::string(i1->begin,i1->end),args,symbols);
1158  }
1159  catch(formula_error& e) {
1160  throw formula_error(e.type, tokens_to_string(begin,end), *i1->filename, i1->line_number);
1161  }
1162  }
1163  }
1164 
1165  throw formula_error("Could not parse expression", tokens_to_string(i1, i2), *i1->filename, i1->line_number);
1166  }
1167  if (op + 1 == end) {
1168  throw formula_error("Expected another token", tokens_to_string(begin,end-1), *op->filename, op->line_number);
1169  }
1170  if(op == i1) {
1171  try{
1172  return expression_ptr(new unary_operator_expression(
1173  std::string(op->begin,op->end),
1174  parse_expression(op+1,i2,symbols)));
1175  }
1176  catch(formula_error& e) {
1177  throw formula_error( e.type, tokens_to_string(begin,end-1), *op->filename, op->line_number);
1178  }
1179  }
1180 
1181  const std::string op_name(op->begin,op->end);
1182 
1183  if(op_name == ".") {
1184  return expression_ptr(new dot_expression(
1185  parse_expression(i1,op,symbols),
1186  parse_expression(op+1,i2,symbols)));
1187  }
1188 
1189  if(op_name == "where") {
1190  expr_table_ptr table(new expr_table());
1191  parse_where_clauses(op+1, i2, table, symbols);
1192  return expression_ptr(new where_expression(parse_expression(i1, op, symbols),
1193  table));
1194  }
1195 
1196  return expression_ptr(new operator_expression(
1197  op_name, parse_expression(i1,op,symbols),
1198  parse_expression(op+1,i2,symbols)));
1199 }
1200 
1201 }
1202 
1204 {
1205  if(managing_symbols) {
1206  delete symbols_;
1207  }
1208 }
1209 
1211 {
1212  if(str.empty()) {
1213  return formula_ptr();
1214  }
1215 
1216  return formula_ptr(new formula(str, symbols));
1217 }
1218 
1220  expr_(),
1221  str_(str),
1222  symbols_(symbols),
1223  managing_symbols(symbols == nullptr)
1224 {
1225  using namespace formula_tokenizer;
1226 
1227  if(symbols == nullptr) {
1229  }
1230 
1231  std::vector<token> tokens;
1232  std::string::const_iterator i1 = str.begin(), i2 = str.end();
1233 
1234  //set true when 'fai' keyword is found
1235  bool fai_keyword = false;
1236  //set true when 'wfl' keyword is found
1237  bool wfl_keyword = false;
1238  //used to locally keep the track of which file we parse actually and in which line we are
1239  std::vector< std::pair< std::string, int> > files;
1240  //used as a source of strings - we point to these strings from tokens
1241  std::set< std::string > filenames;
1242  files.push_back( std::make_pair( "formula", 1 ) );
1243  filenames.insert( "formula" );
1244  std::set< std::string >::iterator filenames_it = filenames.begin();
1245 
1246  while(i1 != i2) {
1247  try {
1248 
1249  tokens.push_back( get_token(i1,i2) );
1250 
1251  formula_tokenizer::TOKEN_TYPE current_type = tokens.back().type;
1252 
1253  if(current_type == TOKEN_WHITESPACE) {
1254  tokens.pop_back();
1255  } else
1256  if( current_type == TOKEN_COMMENT) {
1257  //since we can have multiline comments, let's see how many EOL are within it
1258  int counter = 0;
1259  std::string comment = std::string(tokens.back().begin,tokens.back().end);
1260  for( std::string::iterator str_it = comment.begin(); str_it != comment.end(); ++str_it)
1261  if( *str_it == '\n' )
1262  counter++;
1263 
1264  files.back().second+=counter;
1265  tokens.pop_back();
1266  } else
1267  if( current_type == TOKEN_EOL) {
1268  files.back().second++;
1269  tokens.pop_back();
1270  } else
1271  if( ( current_type == TOKEN_KEYWORD) && ( std::string(tokens.back().begin,tokens.back().end) == "fai") ) {
1272  fai_keyword = true;
1273  tokens.pop_back();
1274  } else
1275  if( ( current_type == TOKEN_KEYWORD) && ( std::string(tokens.back().begin,tokens.back().end) == "wfl") ) {
1276  wfl_keyword = true;
1277  tokens.pop_back();
1278  } else
1279  if( ( current_type == TOKEN_KEYWORD) && ( std::string(tokens.back().begin,tokens.back().end) == "faiend") ) {
1280  if (files.size() > 1) {
1281  files.pop_back();
1282  filenames_it = filenames.find( files.back().first );
1283  tokens.pop_back();
1284  } else {
1285  throw formula_error("Unexpected 'faiend' found", "", "", 0);
1286  }
1287  } else
1288  if( ( current_type == TOKEN_KEYWORD) && ( std::string(tokens.back().begin,tokens.back().end) == "wflend") ) {
1289  if (files.size() > 1) {
1290  files.pop_back();
1291  filenames_it = filenames.find( files.back().first );
1292  tokens.pop_back();
1293  } else {
1294  throw formula_error("Unexpected 'wflend' found", "", "", 0);
1295  }
1296  } else
1297  if (fai_keyword || wfl_keyword) {
1298  if(current_type == TOKEN_STRING_LITERAL) {
1299  std::string str = std::string(tokens.back().begin,tokens.back().end);
1300  files.push_back( std::make_pair( str , 1 ) );
1302  ret = filenames.insert( str );
1303  if(ret.second==true) {
1304  filenames_it = ret.first;
1305  } else {
1306  if (fai_keyword)
1307  throw formula_error("Faifile already included", "fai" + str, "", 0);
1308  else throw formula_error("Wflfile already included", "wfl" + str, "", 0);
1309  }
1310  tokens.pop_back();
1311  fai_keyword = false;
1312  wfl_keyword = false;
1313  } else {
1314  if (fai_keyword)
1315  throw formula_error("Expected string after the 'fai'", "fai", "", 0);
1316  else throw formula_error("Expected string after the 'wfl'", "wfl", "", 0);
1317  }
1318  } else {
1319  //in every token not specified above, store line number and name of file it came from
1320  tokens.back().filename = &(*filenames_it);
1321  tokens.back().line_number = files.back().second;
1322  }
1323  } catch(token_error& e) {
1324  //when we catch token error, we should write whole line in which error occurred, so we merge info from token and everything we had in the line so far
1325  std::string str = "";
1326  if(!tokens.empty()) {
1327  token* tok_it = &tokens[0] + tokens.size()-1;
1328  while( ( tok_it != &tokens[0] ) && (tok_it->line_number == tokens.back().line_number) )
1329  --tok_it;
1330 
1331  if( tok_it != &tokens[0] && tok_it != &tokens[0] + tokens.size() -1)
1332  ++tok_it;
1333 
1334  str = tokens_to_string( tok_it, &tokens[0] + tokens.size() );
1335  }
1336 
1337  throw formula_error(e.description_, str + e.formula_, *filenames_it, files.back().second);
1338  }
1339  }
1340 
1341  if(files.size() > 1) {
1342  throw formula_error("Missing 'wflend', make sure each .wfl file ends with it", "", "", 0);
1343  }
1344 
1345  if(!tokens.empty()) {
1346  expr_ = parse_expression(&tokens[0],&tokens[0] + tokens.size(), symbols_);
1347  } else {
1348  expr_ = expression_ptr(new null_expression());
1349  }
1350 }
1351 
1352 formula::formula(const token* i1, const token* i2, function_symbol_table* symbols) :
1353  expr_(),
1354  str_(),
1355  symbols_(symbols),
1356  managing_symbols(symbols == nullptr)
1357 {
1358  if(symbols == nullptr) {
1360  }
1361 
1362  if(i1 != i2) {
1363  expr_ = parse_expression(i1,i2, symbols);
1364  } else {
1365  expr_ = expression_ptr(new null_expression());
1366  }
1367 }
1368 
1369 variant formula::execute(const formula_callable& variables, formula_debugger *fdb) const
1370 {
1371  try {
1372  return expr_->evaluate(variables, fdb);
1373  } catch(type_error& e) {
1374  std::cerr << "formula type error: " << e.message << "\n";
1375  return variant();
1376  }
1377 }
1378 
1380 {
1381  static map_formula_callable null_callable;
1382  return execute(null_callable,fdb);
1383 }
1384 
1386  const std::string& file, int line)
1387  : error()
1388  , type(type)
1389  , formula(formula)
1390  , filename(file)
1391  , line(line)
1392 {
1393  std::stringstream ss;
1394  ss << "Formula error in " << filename << ":" << line
1395  << "\nIn formula " << formula
1396  << "\nError: " << type;
1397  message = ss.str();
1398 }
1399 
1400 }
1401 
size_t num_elements() const
Definition: variant.cpp:526
std::string str_
Definition: formula.hpp:72
GLuint counter
Definition: glew.h:2584
variant build_range(const variant &v) const
Definition: variant.cpp:1001
const t_terrain NOT
bool is_callable() const
Definition: variant.hpp:100
boost::shared_ptr< formula > formula_ptr
Definition: formula_fwd.hpp:24
std::string id_
Definition: formula.cpp:636
const GLfloat * c
Definition: glew.h:12741
int pos
Definition: formula.cpp:800
expression_ptr right_
Definition: formula.cpp:409
rng * generator
This generator is automatically synced during synced context.
Definition: random_new.cpp:52
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
variant map_
Definition: formula.cpp:306
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:29
static void body(LexState *ls, expdesc *e, int ismethod, int line)
Definition: lparser.cpp:787
TOKEN_TYPE
TOKEN_TYPE is already defined in a Winnt.h (a windows header wich is included under some conditions...
Definition: tokenizer.hpp:24
const game_logic::formula_callable * as_callable() const
Definition: variant.hpp:101
const formula_callable & base_
Definition: formula.cpp:568
boost::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:26
expression_ptr create_function(const std::string &fn, const std::vector< expression_ptr > &args, const function_symbol_table *symbols)
Definition: function.cpp:1632
variant_iterator end() const
Definition: variant.cpp:500
const std::map< variant, variant > & as_map() const
Definition: variant.cpp:617
const std::vector< std::string > items
variant list_elements_sub(const variant &v) const
Definition: variant.cpp:917
bool as_bool() const
Definition: variant.cpp:580
variant list_elements_mul(const variant &v) const
Definition: variant.cpp:935
GLdouble GLdouble t
Definition: glew.h:1366
expression_ptr key_
Definition: formula.cpp:435
variant query_value(const std::string &key) const
Definition: callable.hpp:39
token get_token(iterator &i1, const iterator i2)
Definition: tokenizer.cpp:38
variant list_elements_add(const variant &v) const
Definition: variant.cpp:899
expression_ptr body_
Definition: formula.cpp:614
std::vector< std::string > builtin_function_names()
Definition: function.cpp:1651
GLuint GLuint end
Definition: glew.h:1221
static const char *const id_chars
Definition: formula.hpp:65
static std::string sub(const std::string &s)
Private function to surround an argument with brackets.
void get_inputs(std::vector< formula_input > *inputs) const
Definition: formula.cpp:60
uint32_t next_random()
Provides the next random draw.
Definition: random_new.cpp:76
bool is_list() const
Definition: variant.hpp:92
static formula_ptr create_optional_formula(const std::string &str, function_symbol_table *symbols=nullptr)
Definition: formula.cpp:1210
int as_int() const
Definition: variant.cpp:558
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
variant list_elements_div(const variant &v) const
Definition: variant.cpp:953
variant get_value(const std::string &key) const
Definition: formula.cpp:48
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
void set_value(const std::string &key, const variant &value)
Definition: formula.cpp:70
const formula_callable & global_
Definition: formula.cpp:355
variant list_
Definition: formula.cpp:269
Iterator class for the variant.
Definition: variant.hpp:188
variant concatenate(const variant &v) const
Definition: variant.cpp:971
function_symbol_table * symbols_
Definition: formula.hpp:73
lu_byte right
Definition: lparser.cpp:1020
const_formula_ptr calculation
Definition: formula.cpp:801
GLuint res
Definition: glew.h:9258
variant_iterator begin() const
Definition: variant.cpp:490
boost::shared_ptr< formula_expression > expression_ptr
Definition: formula.hpp:26
formula_debugger * debugger_
Definition: formula.cpp:571
GLint left
Definition: glew.h:5907
bool is_map() const
Definition: variant.hpp:83
static void expr(LexState *ls, expdesc *v)
Definition: lparser.cpp:1066
const std::string & as_string() const
Definition: variant.cpp:603
std::string op_str_
Definition: formula.cpp:214
variant execute(const formula_callable &variables, formula_debugger *fdb=nullptr) const
Definition: formula.cpp:1369
size_t i
Definition: function.cpp:1057
exp_table_evaluated evaluated_table_
Definition: formula.cpp:570
const formula_callable * fallback_
Definition: callable.hpp:173
variant str_
Definition: formula.cpp:804
map_formula_callable & add(const std::string &key, const variant &value)
Definition: formula.cpp:41
std::vector< expression_ptr > items_
Definition: formula.cpp:119
const std::string * filename
Definition: tokenizer.hpp:55
int i_
Definition: formula.cpp:667
std::vector< substitution > subs_
Definition: formula.cpp:805
const formula_callable * fallback_
Definition: function.cpp:807
OP op_
Definition: formula.cpp:213
expr_table_ptr clauses_
Definition: formula.cpp:615
const formula_callable & local_
Definition: formula.cpp:355
std::vector< std::string > parenthetical_split(std::string const &val, const char separator, std::string const &left, std::string const &right, const int flags)
Splits a string based either on a separator where text within parenthesis is protected from splitting...
GLclampd n
Definition: glew.h:5903
bool find(E event, F functor)
Tests whether an event handler is available.
variant string_
Definition: formula.cpp:219
boost::shared_ptr< formula_function > formula_function_ptr
Definition: function.hpp:133
variant get_member(const std::string &str) const
Definition: variant.cpp:545
std::string message
Definition: exceptions.hpp:29
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
std::map< std::string, variant > values_
Definition: callable.hpp:172
virtual void set_value(const std::string &key, const variant &value)
Definition: formula.cpp:29
expression_ptr left_
Definition: formula.cpp:409
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
#define e
expression_ptr expr_
Definition: formula.hpp:71
expr_table_ptr table_
Definition: formula.cpp:569
map_formula_callable(const formula_callable *fallback=nullptr)
Definition: formula.cpp:35
bool is_string() const
Definition: variant.hpp:79
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
GLdouble s
Definition: glew.h:1358
expression_ptr operand_
Definition: formula.cpp:215
int f_
Definition: formula.cpp:689
virtual void get_inputs(std::vector< formula_input > *) const
Definition: callable.hpp:64
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glew.h:3780
GLsizei const GLcharARB ** string
Definition: glew.h:4503
expression_ptr expr_
Definition: function.cpp:806
const std::string valid
Little parts of regex templates used to parse Wml annoations.
GLclampf f
Definition: glew.h:3024
function_symbol_table * symbols_
Definition: formula.cpp:99