00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "global.hpp"
00014
00015 #include <algorithm>
00016 #include <boost/lexical_cast.hpp>
00017 #include <cmath>
00018 #include <iostream>
00019 #include <vector>
00020
00021
00022 #include "formula.hpp"
00023 #include "formula_callable.hpp"
00024 #include "formula_function.hpp"
00025 #include "formula_tokenizer.hpp"
00026 #include "map_utils.hpp"
00027
00028 namespace game_logic
00029 {
00030
00031 void formula_callable::set_value(const std::string& key, const variant& )
00032 {
00033 std::cerr << "ERROR: cannot set key '" << key << "' on object\n";
00034 }
00035
00036 map_formula_callable::map_formula_callable(
00037 const formula_callable* fallback) : fallback_(fallback)
00038 {}
00039
00040 map_formula_callable& map_formula_callable::add(const std::string& key,
00041 const variant& value)
00042 {
00043 values_[key] = value;
00044 return *this;
00045 }
00046
00047 variant map_formula_callable::get_value(const std::string& key) const
00048 {
00049 return map_get_value_default(values_, key,
00050 fallback_ ? fallback_->query_value(key) : variant());
00051 }
00052
00053 void map_formula_callable::get_inputs(std::vector<formula_input>* inputs) const
00054 {
00055 if(fallback_) {
00056 fallback_->get_inputs(inputs);
00057 }
00058 for(std::map<std::string,variant>::const_iterator i = values_.begin(); i != values_.end(); ++i) {
00059 inputs->push_back(formula_input(i->first, FORMULA_READ_WRITE));
00060 }
00061 }
00062
00063 void map_formula_callable::set_value(const std::string& key, const variant& value)
00064 {
00065 values_[key] = value;
00066 }
00067
00068 namespace {
00069
00070 class function_list_expression : public formula_expression {
00071 public:
00072 explicit function_list_expression(function_symbol_table *symbols)
00073 : symbols_(symbols)
00074 {}
00075
00076 private:
00077 variant execute(const formula_callable& ) const {
00078 std::vector<variant> res;
00079 std::vector<std::string> function_names = builtin_function_names();
00080 std::vector<std::string> more_function_names = symbols_->get_function_names();
00081 function_names.insert(function_names.end(), more_function_names.begin(), more_function_names.end());
00082 for(size_t i = 0; i < function_names.size(); i++) {
00083 res.push_back(variant(function_names[i]));
00084 }
00085 return variant(&res);
00086 }
00087
00088 function_symbol_table* symbols_;
00089 };
00090
00091 class list_expression : public formula_expression {
00092 public:
00093 explicit list_expression(const std::vector<expression_ptr>& items)
00094 : items_(items)
00095 {}
00096
00097 private:
00098 variant execute(const formula_callable& variables) const {
00099 std::vector<variant> res;
00100 res.reserve(items_.size());
00101 for(std::vector<expression_ptr>::const_iterator i = items_.begin(); i != items_.end(); ++i) {
00102 res.push_back((*i)->evaluate(variables));
00103 }
00104
00105 return variant(&res);
00106 }
00107
00108 std::vector<expression_ptr> items_;
00109 };
00110
00111 class map_expression : public formula_expression {
00112 public:
00113 explicit map_expression(const std::vector<expression_ptr>& items)
00114 : items_(items)
00115 {}
00116
00117 private:
00118 variant execute(const formula_callable& variables) const {
00119 std::map<variant,variant> res;
00120 for(std::vector<expression_ptr>::const_iterator i = items_.begin(); ( i != items_.end() ) && ( i+1 != items_.end() ) ; i+=2) {
00121 variant key = (*i)->evaluate(variables);
00122 variant value = (*(i+1))->evaluate(variables);
00123 res[ key ] = value;
00124 }
00125
00126 return variant(&res);
00127 }
00128
00129 std::vector<expression_ptr> items_;
00130 };
00131
00132 class unary_operator_expression : public formula_expression {
00133 public:
00134 unary_operator_expression(const std::string& op, expression_ptr arg)
00135 : operand_(arg)
00136 {
00137 if(op == "not") {
00138 op_ = NOT;
00139 } else if(op == "-") {
00140 op_ = SUB;
00141 } else {
00142 std::cerr << "illegal unary operator: '" << op << "'\n";
00143 throw formula_error();
00144 }
00145 }
00146 private:
00147 variant execute(const formula_callable& variables) const {
00148 const variant res = operand_->evaluate(variables);
00149 switch(op_) {
00150 case NOT:
00151 return res.as_bool() ? variant(0) : variant(1);
00152 case SUB:
00153 default:
00154 return -res;
00155 }
00156 }
00157 enum OP { NOT, SUB };
00158 OP op_;
00159 expression_ptr operand_;
00160 };
00161
00162 class list_callable : public formula_callable {
00163 variant list_;
00164 public:
00165 explicit list_callable(const variant& list) : list_(list)
00166 {}
00167
00168 void get_inputs(std::vector<formula_input>* inputs) const {
00169 inputs->push_back(formula_input("size", FORMULA_READ_WRITE));
00170 inputs->push_back(formula_input("empty", FORMULA_READ_WRITE));
00171 inputs->push_back(formula_input("first", FORMULA_READ_WRITE));
00172 inputs->push_back(formula_input("last", FORMULA_READ_WRITE));
00173 }
00174
00175 variant get_value(const std::string& key) const {
00176 if(key == "size") {
00177 return variant(list_.num_elements());
00178 } else if(key == "empty") {
00179 return variant(list_.num_elements() == 0);
00180 } else if(key == "first") {
00181 if(list_.num_elements() > 0) {
00182 return list_[0];
00183 } else {
00184 return variant();
00185 }
00186 } else if(key == "last") {
00187 if(list_.num_elements() > 0) {
00188 return list_[list_.num_elements()-1];
00189 } else {
00190 return variant();
00191 }
00192 } else {
00193 return variant();
00194 }
00195 }
00196 };
00197
00198 class dot_expression : public formula_expression {
00199 public:
00200 dot_expression(expression_ptr left, expression_ptr right)
00201 : left_(left), right_(right)
00202 {}
00203 private:
00204 variant execute(const formula_callable& variables) const {
00205 const variant left = left_->evaluate(variables);
00206 if(!left.is_callable()) {
00207 if(left.is_list()) {
00208 return right_->evaluate(list_callable(left));
00209 }
00210
00211 return left;
00212 }
00213
00214 return right_->evaluate(*left.as_callable());
00215 }
00216
00217 expression_ptr left_, right_;
00218 };
00219
00220 class square_bracket_expression : public formula_expression {
00221 public:
00222 square_bracket_expression(expression_ptr left, expression_ptr key)
00223 : left_(left), key_(key)
00224 {}
00225 private:
00226 variant execute(const formula_callable& variables) const {
00227 const variant left = left_->evaluate(variables);
00228 const variant key = key_->evaluate(variables);
00229 if(left.is_list() || left.is_map()) {
00230 return left[ key ];
00231 } else {
00232 std::cerr << "illegal usage of operator []'\n";
00233 throw formula_error();
00234 }
00235 }
00236
00237 expression_ptr left_, key_;
00238 };
00239
00240 class operator_expression : public formula_expression {
00241 public:
00242 operator_expression(const std::string& op, expression_ptr left,
00243 expression_ptr right)
00244 : op_(OP(op[0])), left_(left), right_(right)
00245 {
00246 if(op == ">=") {
00247 op_ = GTE;
00248 } else if(op == "<=") {
00249 op_ = LTE;
00250 } else if(op == "!=") {
00251 op_ = NEQ;
00252 } else if(op == "and") {
00253 op_ = AND;
00254 } else if(op == "or") {
00255 op_ = OR;
00256 }
00257 }
00258
00259 private:
00260 variant execute(const formula_callable& variables) const {
00261 const variant left = left_->evaluate(variables);
00262 const variant right = right_->evaluate(variables);
00263 switch(op_) {
00264 case AND:
00265 return left.as_bool() == false ? left : right;
00266 case OR:
00267 return left.as_bool() ? left : right;
00268 case ADD:
00269 return left + right;
00270 case SUB:
00271 return left - right;
00272 case MUL:
00273 return left * right;
00274 case DIV:
00275 return left / right;
00276 case POW:
00277 return left ^ right;
00278 case EQ:
00279 return left == right ? variant(1) : variant(0);
00280 case NEQ:
00281 return left != right ? variant(1) : variant(0);
00282 case LTE:
00283 return left <= right ? variant(1) : variant(0);
00284 case GTE:
00285 return left >= right ? variant(1) : variant(0);
00286 case LT:
00287 return left < right ? variant(1) : variant(0);
00288 case GT:
00289 return left > right ? variant(1) : variant(0);
00290 case MOD:
00291 return left % right;
00292 case DICE:
00293 default:
00294 return variant(dice_roll(left.as_int(), right.as_int()));
00295 }
00296 }
00297
00298 static int dice_roll(int num_rolls, int faces) {
00299 int res = 0;
00300 while(faces > 0 && num_rolls-- > 0) {
00301 res += (rand()%faces)+1;
00302 }
00303 return res;
00304 }
00305
00306 enum OP { AND, OR, NEQ, LTE, GTE, GT='>', LT='<', EQ='=',
00307 ADD='+', SUB='-', MUL='*', DIV='/', DICE='d', POW='^', MOD='%' };
00308
00309 OP op_;
00310 expression_ptr left_, right_;
00311 };
00312
00313 typedef std::map<std::string,expression_ptr> expr_table;
00314 typedef boost::shared_ptr<expr_table> expr_table_ptr;
00315
00316 class where_variables: public formula_callable {
00317 public:
00318 where_variables(const formula_callable &base,
00319 expr_table_ptr table )
00320 : base_(base), table_(table) { }
00321 private:
00322 const formula_callable& base_;
00323 expr_table_ptr table_;
00324
00325 void get_inputs(std::vector<formula_input>* inputs) const {
00326 for(expr_table::const_iterator i = table_->begin(); i != table_->end(); ++i) {
00327 inputs->push_back(formula_input(i->first, FORMULA_READ_ONLY));
00328 }
00329 }
00330
00331 variant get_value(const std::string& key) const {
00332 expr_table::iterator i = table_->find(key);
00333 if(i != table_->end()) {
00334 return i->second->evaluate(base_);
00335 }
00336 return base_.query_value(key);
00337 }
00338 };
00339
00340 class where_expression: public formula_expression {
00341 public:
00342 explicit where_expression(expression_ptr body,
00343 expr_table_ptr clauses)
00344 : body_(body), clauses_(clauses)
00345 {}
00346
00347 private:
00348 expression_ptr body_;
00349 expr_table_ptr clauses_;
00350
00351 variant execute(const formula_callable& variables) const {
00352 where_variables wrapped_variables(variables, clauses_);
00353 return body_->evaluate(wrapped_variables);
00354 }
00355 };
00356
00357
00358 class identifier_expression : public formula_expression {
00359 public:
00360 explicit identifier_expression(const std::string& id) : id_(id)
00361 {}
00362 private:
00363 variant execute(const formula_callable& variables) const {
00364 return variables.query_value(id_);
00365 }
00366 std::string id_;
00367 };
00368
00369 class null_expression : public formula_expression {
00370 public:
00371 explicit null_expression() {};
00372 private:
00373 variant execute(const formula_callable& ) const {
00374 return variant();
00375 }
00376 };
00377
00378
00379 class integer_expression : public formula_expression {
00380 public:
00381 explicit integer_expression(int i) : i_(i)
00382 {}
00383 private:
00384 variant execute(const formula_callable& ) const {
00385 return variant(i_);
00386 }
00387
00388 int i_;
00389 };
00390
00391 class string_expression : public formula_expression {
00392 public:
00393 explicit string_expression(std::string str)
00394 {
00395 std::string::iterator i;
00396 while((i = std::find(str.begin(), str.end(), '{')) != str.end()) {
00397 std::string::iterator j = std::find(i, str.end(), '}');
00398 if(j == str.end()) {
00399 break;
00400 }
00401
00402 const std::string formula_str(i+1, j);
00403 const int pos = i - str.begin();
00404 str.erase(i, j+1);
00405
00406 substitution sub;
00407 sub.pos = pos;
00408 sub.calculation.reset(new formula(formula_str));
00409 subs_.push_back(sub);
00410 }
00411
00412 std::reverse(subs_.begin(), subs_.end());
00413
00414 str_ = variant(str);
00415 }
00416 private:
00417 variant execute(const formula_callable& variables) const {
00418 if(subs_.empty()) {
00419 return str_;
00420 } else {
00421 std::string res = str_.as_string();
00422 for(size_t i=0; i < subs_.size(); ++i) {
00423 const substitution& sub = subs_[i];
00424 const std::string str = sub.calculation->execute(variables).string_cast();
00425 res.insert(sub.pos, str);
00426 }
00427
00428 return variant(res);
00429 }
00430 }
00431
00432 struct substitution {
00433 int pos;
00434 const_formula_ptr calculation;
00435 };
00436
00437 variant str_;
00438 std::vector<substitution> subs_;
00439 };
00440
00441 using namespace formula_tokenizer;
00442 int operator_precedence(const token& t)
00443 {
00444 static std::map<std::string,int> precedence_map;
00445 if(precedence_map.empty()) {
00446 int n = 0;
00447 precedence_map["not"] = ++n;
00448 precedence_map["where"] = ++n;
00449 precedence_map["or"] = ++n;
00450 precedence_map["and"] = ++n;
00451 precedence_map["="] = ++n;
00452 precedence_map["!="] = n;
00453 precedence_map["<"] = n;
00454 precedence_map[">"] = n;
00455 precedence_map["<="] = n;
00456 precedence_map[">="] = n;
00457 precedence_map["+"] = ++n;
00458 precedence_map["-"] = n;
00459 precedence_map["*"] = ++n;
00460 precedence_map["/"] = ++n;
00461 precedence_map["%"] = ++n;
00462 precedence_map["^"] = ++n;
00463 precedence_map["d"] = ++n;
00464 precedence_map["."] = ++n;
00465 }
00466
00467 assert(precedence_map.count(std::string(t.begin,t.end)));
00468 return precedence_map[std::string(t.begin,t.end)];
00469 }
00470
00471 expression_ptr parse_expression(const token* i1, const token* i2, function_symbol_table* symbols);
00472
00473 void parse_function_args(const token* &i1, const token* i2,
00474 std::vector<std::string>* res)
00475 {
00476 if(i1->type == TOKEN_LPARENS) {
00477 ++i1;
00478 } else {
00479 std::cerr << "Invalid function definition" << std::endl;
00480 throw formula_error();
00481 }
00482
00483 while((i1-> type != TOKEN_RPARENS) && (i1 != i2)) {
00484 if(i1->type == TOKEN_IDENTIFIER) {
00485 if(std::string((i1+1)->begin, (i1+1)->end) == "*") {
00486 res->push_back(std::string(i1->begin, i1->end) + std::string("*"));
00487 ++i1;
00488 } else {
00489 res->push_back(std::string(i1->begin, i1->end));
00490 }
00491 } else if (i1->type == TOKEN_COMMA) {
00492
00493 } else {
00494 std::cerr << "Invalid function definition" << std::endl;
00495 throw formula_error();
00496 }
00497 ++i1;
00498 }
00499
00500 if(i1->type != TOKEN_RPARENS) {
00501 std::cerr << "Invalid function definition" << std::endl;
00502 throw formula_error();
00503 }
00504 ++i1;
00505 }
00506
00507 void parse_args(const token* i1, const token* i2,
00508 std::vector<expression_ptr>* res,
00509 function_symbol_table* symbols)
00510 {
00511 int parens = 0;
00512 const token* beg = i1;
00513 while(i1 != i2) {
00514 if(i1->type == TOKEN_LPARENS || i1->type == TOKEN_LSQUARE || i1->type == TOKEN_LBRACKET ) {
00515 ++parens;
00516 } else if(i1->type == TOKEN_RPARENS || i1->type == TOKEN_RSQUARE || i1->type == TOKEN_RBRACKET) {
00517 --parens;
00518 } else if(i1->type == TOKEN_COMMA && !parens) {
00519 res->push_back(parse_expression(beg,i1, symbols));
00520 beg = i1+1;
00521 }
00522
00523 ++i1;
00524 }
00525
00526 if(beg != i1) {
00527 res->push_back(parse_expression(beg,i1, symbols));
00528 }
00529 }
00530
00531 void parse_set_args(const token* i1, const token* i2,
00532 std::vector<expression_ptr>* res,
00533 function_symbol_table* symbols)
00534 {
00535 int parens = 0;
00536 bool check_pointer = false;
00537 const token* beg = i1;
00538 while(i1 != i2) {
00539 if(i1->type == TOKEN_LPARENS || i1->type == TOKEN_LSQUARE) {
00540 ++parens;
00541 } else if(i1->type == TOKEN_RPARENS || i1->type == TOKEN_RSQUARE) {
00542 --parens;
00543 } else if( i1->type == TOKEN_POINTER && !parens ) {
00544 if (!check_pointer) {
00545 check_pointer = true;
00546 res->push_back(parse_expression(beg,i1, symbols));
00547 beg = i1+1;
00548 } else {
00549 std::cerr << "Too many '->' operators\n";
00550 throw formula_error();
00551 }
00552 } else if( i1->type == TOKEN_COMMA && !parens ) {
00553 check_pointer = false;
00554 res->push_back(parse_expression(beg,i1, symbols));
00555 beg = i1+1;
00556 }
00557
00558 ++i1;
00559 }
00560
00561 if(beg != i1) {
00562 res->push_back(parse_expression(beg,i1, symbols));
00563 }
00564 }
00565
00566 void parse_where_clauses(const token* i1, const token * i2,
00567 expr_table_ptr res, function_symbol_table* symbols) {
00568 int parens = 0;
00569 const token *original_i1_cached = i1;
00570 const token *beg = i1;
00571 std::string var_name;
00572 while(i1 != i2) {
00573 if(i1->type == TOKEN_LPARENS) {
00574 ++parens;
00575 } else if(i1->type == TOKEN_RPARENS) {
00576 --parens;
00577 } else if(!parens) {
00578 if(i1->type == TOKEN_COMMA) {
00579 if(var_name.empty()) {
00580 std::cerr << "There is 'where <expression>,; "
00581 << "'where name=<expression>,' was needed.\n";
00582 throw formula_error();
00583 }
00584 (*res)[var_name] = parse_expression(beg,i1, symbols);
00585 beg = i1+1;
00586 var_name = "";
00587 } else if(i1->type == TOKEN_OPERATOR) {
00588 std::string op_name(i1->begin, i1->end);
00589 if(op_name == "=") {
00590 if(beg->type != TOKEN_IDENTIFIER) {
00591 if(i1 == original_i1_cached) {
00592 std::cerr<< "There is 'where =<expression'; "
00593 << "'where name=<expression>' was needed.\n";
00594 } else {
00595 std::cerr<< "There is 'where <expression>=<expression>'; "
00596 << "'where name=<expression>' was needed.\n";
00597 }
00598 throw formula_error();
00599 } else if(beg+1 != i1) {
00600 std::cerr<<"There is 'where name <expression>=<expression>'; "
00601 << "'where name=<expression>' was needed.\n";
00602 throw formula_error();
00603 } else if(!var_name.empty()) {
00604 std::cerr<<"There is 'where name=name=<expression>'; "
00605 <<"'where name=<expression>' was needed.\n";
00606 throw formula_error();
00607 }
00608 var_name.insert(var_name.end(), beg->begin, beg->end);
00609 beg = i1+1;
00610 }
00611 }
00612 }
00613 ++i1;
00614 }
00615 if(beg != i1) {
00616 if(var_name.empty()) {
00617 std::cerr << "There is 'where <expression>'; "
00618 << "'where name=<expression> was needed.\n";
00619 throw formula_error();
00620 }
00621 (*res)[var_name] = parse_expression(beg,i1, symbols);
00622 }
00623 }
00624
00625 expression_ptr parse_expression(const token* i1, const token* i2, function_symbol_table* symbols)
00626 {
00627 if(i1 == i2) {
00628 std::cerr << "empty expression\n";
00629 throw formula_error();
00630 }
00631
00632 if(i1->type == TOKEN_KEYWORD &&
00633 (i1+1)->type == TOKEN_IDENTIFIER) {
00634 if(std::string(i1->begin, i1->end) == "def") {
00635 ++i1;
00636 const std::string formula_name = std::string(i1->begin, i1->end);
00637 std::vector<std::string> args;
00638 parse_function_args(++i1, i2, &args);
00639 const token* beg = i1;
00640 while((i1 != i2) && (i1->type != TOKEN_SEMICOLON)) {
00641 ++i1;
00642 }
00643 const std::string formula_str = std::string(beg->begin, (i1-1)->end);
00644 const std::string precond = "";
00645 symbols->add_formula_function(formula_name,
00646 const_formula_ptr(new formula(formula_str, symbols)),
00647 formula::create_optional_formula(precond, symbols),
00648 args);
00649 if((i1 == i2) || (i1 == (i2-1))) {
00650 return expression_ptr(new function_list_expression(symbols));
00651 }
00652 else {
00653 return parse_expression((i1+1), i2, symbols);
00654 }
00655 }
00656 }
00657
00658 int parens = 0;
00659 const token* op = NULL;
00660 for(const token* i = i1; i != i2; ++i) {
00661 if(i->type == TOKEN_LPARENS || i->type == TOKEN_LSQUARE) {
00662 ++parens;
00663 } else if(i->type == TOKEN_RPARENS || i->type == TOKEN_RSQUARE) {
00664 --parens;
00665 } else if(parens == 0 && i->type == TOKEN_OPERATOR) {
00666 if(op == NULL || operator_precedence(*op) >
00667 operator_precedence(*i)) {
00668 op = i;
00669 }
00670 }
00671 }
00672
00673 if(op == NULL) {
00674 if(i1->type == TOKEN_LPARENS && (i2-1)->type == TOKEN_RPARENS) {
00675 return parse_expression(i1+1,i2-1,symbols);
00676 } else if( (i2-1)->type == TOKEN_RSQUARE) {
00677 const token* tok = i2-2;
00678 int square_parens = 0;
00679 while ( (tok->type != TOKEN_LSQUARE || square_parens) && tok != i1) {
00680 if (tok->type == TOKEN_RSQUARE) {
00681 square_parens++;
00682 } else if(tok->type == TOKEN_LSQUARE) {
00683 square_parens--;
00684 }
00685 --tok;
00686 }
00687 if (tok->type == TOKEN_LSQUARE) {
00688 if (tok == i1) {
00689
00690 std::vector<expression_ptr> args;
00691 parse_args(i1+1,i2-1,&args,symbols);
00692 return expression_ptr(new list_expression(args));
00693 } else {
00694
00695 return expression_ptr(new square_bracket_expression(
00696 parse_expression(i1,tok,symbols),
00697 parse_expression(tok+1,i2-1,symbols)));
00698 }
00699 }
00700 } else if(i1->type == TOKEN_LBRACKET && (i2-1)->type == TOKEN_RBRACKET) {
00701
00702 std::vector<expression_ptr> args;
00703 parse_set_args(i1+1,i2-1,&args,symbols);
00704 return expression_ptr(new map_expression(args));
00705 } else if(i2 - i1 == 1) {
00706 if(i1->type == TOKEN_KEYWORD) {
00707 if(std::string(i1->begin,i1->end) == "functions") {
00708 return expression_ptr(new function_list_expression(symbols));
00709 }
00710 } else if(i1->type == TOKEN_IDENTIFIER) {
00711 return expression_ptr(new identifier_expression(
00712 std::string(i1->begin,i1->end)));
00713 } else if(i1->type == TOKEN_INTEGER) {
00714 int n = boost::lexical_cast<int>(std::string(i1->begin,i1->end));
00715 return expression_ptr(new integer_expression(n));
00716 } else if(i1->type == TOKEN_STRING_LITERAL) {
00717 return expression_ptr(new string_expression(std::string(i1->begin+1,i1->end-1)));
00718 }
00719 } else if(i1->type == TOKEN_IDENTIFIER &&
00720 (i1+1)->type == TOKEN_LPARENS &&
00721 (i2-1)->type == TOKEN_RPARENS) {
00722 int nleft = 0, nright = 0;
00723 for(const token* i = i1; i != i2; ++i) {
00724 if(i->type == TOKEN_LPARENS) {
00725 ++nleft;
00726 } else if(i->type == TOKEN_RPARENS) {
00727 ++nright;
00728 }
00729 }
00730
00731 if(nleft == nright) {
00732 std::vector<expression_ptr> args;
00733 parse_args(i1+2,i2-1,&args,symbols);
00734 return expression_ptr(
00735 create_function(std::string(i1->begin,i1->end),args,symbols));
00736 }
00737 }
00738
00739 std::ostringstream expr;
00740 while(i1 != i2) {
00741 expr << std::string(i1->begin,i1->end);
00742 ++i1;
00743 }
00744 std::cerr << "could not parse expression: '" << expr.str() << "'\n";
00745 throw formula_error();
00746 }
00747
00748 if(op == i1) {
00749 return expression_ptr(new unary_operator_expression(
00750 std::string(op->begin,op->end),
00751 parse_expression(op+1,i2,symbols)));
00752 }
00753
00754 const std::string op_name(op->begin,op->end);
00755
00756 if(op_name == ".") {
00757 return expression_ptr(new dot_expression(
00758 parse_expression(i1,op,symbols),
00759 parse_expression(op+1,i2,symbols)));
00760 }
00761
00762 if(op_name == "where") {
00763 expr_table_ptr table(new expr_table());
00764 parse_where_clauses(op+1, i2, table, symbols);
00765 return expression_ptr(new where_expression(parse_expression(i1, op, symbols),
00766 table));
00767 }
00768
00769 return expression_ptr(new operator_expression(
00770 op_name, parse_expression(i1,op,symbols),
00771 parse_expression(op+1,i2,symbols)));
00772 }
00773
00774 }
00775
00776 formula_ptr formula::create_string_formula(const std::string& str)
00777 {
00778 formula_ptr res(new formula());
00779 res->expr_.reset(new string_expression(str));
00780 return res;
00781 }
00782
00783 formula_ptr formula::create_optional_formula(const std::string& str, function_symbol_table* symbols)
00784 {
00785 if(str.empty()) {
00786 return formula_ptr();
00787 }
00788
00789 try {
00790 return formula_ptr(new formula(str, symbols));
00791 } catch(...) {
00792 std::cerr << "ERROR parsing optional formula: '" << str << "'\n";
00793 return formula_ptr();
00794 }
00795 }
00796
00797 formula::formula(const std::string& str, function_symbol_table* symbols) : str_(str)
00798 {
00799 using namespace formula_tokenizer;
00800
00801 std::vector<token> tokens;
00802 std::string::const_iterator i1 = str.begin(), i2 = str.end();
00803 while(i1 != i2) {
00804 try {
00805 tokens.push_back(get_token(i1,i2));
00806 if((tokens.back().type == TOKEN_WHITESPACE) || (tokens.back().type == TOKEN_COMMENT)) {
00807 tokens.pop_back();
00808 }
00809 } catch(token_error& ) {
00810 throw formula_error();
00811 }
00812 }
00813
00814 try {
00815 if(tokens.size() != 0) {
00816 expr_ = parse_expression(&tokens[0],&tokens[0] + tokens.size(), symbols);
00817 } else {
00818 expr_ = expression_ptr(new null_expression());
00819 }
00820 } catch(...) {
00821 std::cerr << "error parsing formula '" << str << "'\n";
00822 throw;
00823 }
00824 }
00825
00826 variant formula::execute(const formula_callable& variables) const
00827 {
00828 try {
00829 return expr_->evaluate(variables);
00830 } catch(type_error& e) {
00831 std::cerr << "formula type error: " << e.message << "\n";
00832 return variant();
00833 }
00834 }
00835
00836 variant formula::execute() const
00837 {
00838 static map_formula_callable null_callable;
00839 return execute(null_callable);
00840 }
00841
00842 }
00843
00844 #ifdef UNIT_TEST_FORMULA
00845 using namespace game_logic;
00846 class mock_char : public formula_callable {
00847 variant get_value(const std::string& key) const {
00848 if(key == "strength") {
00849 return variant(15);
00850 } else if(key == "agility") {
00851 return variant(12);
00852 }
00853
00854 return variant(10);
00855 }
00856 };
00857 class mock_party : public formula_callable {
00858 variant get_value(const std::string& key) const {
00859 if(key == "members") {
00860 i_[0].add("strength",variant(12));
00861 i_[1].add("strength",variant(16));
00862 i_[2].add("strength",variant(14));
00863 std::vector<variant> members;
00864 for(int n = 0; n != 3; ++n) {
00865 members.push_back(variant(&i_[n]));
00866 }
00867
00868 return variant(&members);
00869 } else if(key == "char") {
00870 return variant(&c_);
00871 } else {
00872 return variant(0);
00873 }
00874 }
00875
00876 mock_char c_;
00877 mutable map_formula_callable i_[3];
00878
00879 };
00880
00881 #include <time.h>
00882
00883 int main()
00884 {
00885 srand(time(NULL));
00886 mock_char c;
00887 mock_party p;
00888 try {
00889 assert(formula("strength").execute(c).as_int() == 15);
00890 assert(formula("17").execute(c).as_int() == 17);
00891 assert(formula("strength/2 + agility").execute(c).as_int() == 19);
00892 assert(formula("(strength+agility)/2").execute(c).as_int() == 13);
00893 assert(formula("strength > 12").execute(c).as_int() == 1);
00894 assert(formula("strength > 18").execute(c).as_int() == 0);
00895 assert(formula("if(strength > 12, 7, 2)").execute(c).as_int() == 7);
00896 assert(formula("if(strength > 18, 7, 2)").execute(c).as_int() == 2);
00897 assert(formula("2 and 1").execute(c).as_int() == 1);
00898 assert(formula("2 and 0").execute(c).as_int() == 0);
00899 assert(formula("2 or 0").execute(c).as_int() == 1);
00900 assert(formula("-5").execute(c).as_int() == -5);
00901 assert(formula("not 5").execute(c).as_int() == 0);
00902 assert(formula("not 0").execute(c).as_int() == 1);
00903 assert(formula("abs(5)").execute(c).as_int() == 5);
00904 assert(formula("abs(-5)").execute(c).as_int() == 5);
00905 assert(formula("min(3,5)").execute(c).as_int() == 3);
00906 assert(formula("min(5,2)").execute(c).as_int() == 2);
00907 assert(formula("max(3,5)").execute(c).as_int() == 5);
00908 assert(formula("max(5,2)").execute(c).as_int() == 5);
00909 assert(formula("max(4,5,[2,18,7])").execute(c).as_int() == 18);
00910 assert(formula("char.strength").execute(p).as_int() == 15);
00911 assert(formula("choose(members,strength).strength").execute(p).as_int() == 16);
00912 assert(formula("4^2").execute().as_int() == 16);
00913 assert(formula("2+3^3").execute().as_int() == 29);
00914 assert(formula("2*3^3+2").execute().as_int() == 56);
00915 assert(formula("9^3").execute().as_int() == 729);
00916 assert(formula("x*5 where x=1").execute().as_int() == 5);
00917 assert(formula("x*(a*b where a=2,b=1) where x=5").execute().as_int() == 10);
00918 assert(formula("char.strength * ability where ability=3").execute(p).as_int() == 45);
00919 assert(formula("'abcd' = 'abcd'").execute(p).as_bool() == true);
00920 assert(formula("'abcd' = 'acd'").execute(p).as_bool() == false);
00921 assert(formula("'strength, agility: {strength}, {agility}'").execute(c).as_string() ==
00922 "strength, agility: 15, 12");
00923 const int dice_roll = formula("3d6").execute().as_int();
00924 assert(dice_roll >= 3 && dice_roll <= 18);
00925
00926 assert(formula::create_string_formula("Your strength is {strength}")->execute(c).as_string() ==
00927 "Your strength is 15");
00928 variant myarray = formula("[1,2,3]").execute();
00929 assert(myarray.num_elements() == 3);
00930 assert(myarray[0].as_int() == 1);
00931 assert(myarray[1].as_int() == 2);
00932 assert(myarray[2].as_int() == 3);
00933 } catch(formula_error& e) {
00934 std::cerr << "parse error\n";
00935 }
00936 }
00937 #endif