diff --git a/src/ai/formula/function_table.cpp b/src/ai/formula/function_table.cpp index 2f063f07d49..fcab868cb1b 100644 --- a/src/ai/formula/function_table.cpp +++ b/src/ai/formula/function_table.cpp @@ -1133,18 +1133,6 @@ private: }; -class set_var_function : public function_expression { -public: - explicit set_var_function(const args_list& args) - : function_expression("set_var", args, 2, 2) - {} -private: - variant execute(const formula_callable& variables, formula_debugger *fdb) const { - return variant(new set_var_callable(args()[0]->evaluate(variables,add_debug_info(fdb,0,"set_var:key")).as_string(), args()[1]->evaluate(variables,add_debug_info(fdb,1,"set_var:value")))); - } -}; - - class set_unit_var_function : public function_expression { public: explicit set_unit_var_function(const args_list& args) @@ -1191,21 +1179,6 @@ private: } }; - -class safe_call_function : public function_expression { -public: - explicit safe_call_function(const args_list& args) - : function_expression("safe_call", args, 2, 2) - {} -private: - variant execute(const formula_callable& variables, formula_debugger *fdb) const { - const variant main = args()[0]->evaluate(variables,fdb); - const expression_ptr backup_formula = args()[1]; - - return variant(new safe_call_callable(main, backup_formula)); - } -}; - class debug_label_function : public function_expression { public: explicit debug_label_function(const args_list& args, const formula_ai& ai) @@ -1623,7 +1596,7 @@ public: #define FUNCTION(name) add_function(#name, formula_function_ptr( \ new builtin_formula_function(#name))) -ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) { +ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) : function_symbol_table(new action_function_symbol_table) { FUNCTION(outcomes); //AI_FUNCTION(evaluate_for_position); FUNCTION(move); @@ -1632,14 +1605,12 @@ ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) { AI_FUNCTION(rate_action); FUNCTION(recall); FUNCTION(recruit); - FUNCTION(safe_call); FUNCTION(get_unit_type); AI_FUNCTION(is_avoided_location); FUNCTION(is_village); AI_FUNCTION(is_unowned_village); FUNCTION(unit_at); AI_FUNCTION(unit_moves); - FUNCTION(set_var); FUNCTION(set_unit_var); FUNCTION(fallback); FUNCTION(units_can_reach); diff --git a/src/formula/formula.cpp b/src/formula/formula.cpp index 4b73c1b72f8..9cb13c1161b 100644 --- a/src/formula/formula.cpp +++ b/src/formula/formula.cpp @@ -86,11 +86,8 @@ public: private: variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const { std::vector res; - std::vector function_names = builtin_function_names(); - std::vector more_function_names = symbols_->get_function_names(); - function_names.insert(function_names.end(), more_function_names.begin(), more_function_names.end()); - for(size_t i = 0; i < function_names.size(); i++) { - res.emplace_back(function_names[i]); + for(const std::string& fcn_name : symbols_->get_function_names()) { + res.emplace_back(fcn_name); } return variant(res); } @@ -1001,6 +998,12 @@ expression_ptr parse_expression(const token* i1, const token* i2, function_symbo throw formula_error("Empty expression", "", *i1->filename, i1->line_number); } + std::unique_ptr temp_functions; + if(!symbols) { + temp_functions.reset(new function_symbol_table(function_symbol_table::get_builtins())); + symbols = temp_functions.get(); + } + const token* begin = i1, *end = i2; //these are used for error reporting if(i1->type == TOKEN_KEYWORD && @@ -1153,7 +1156,7 @@ expression_ptr parse_expression(const token* i1, const token* i2, function_symbo std::vector args; parse_args(i1+2,i2-1,&args,symbols); try{ - return create_function(std::string(i1->begin,i1->end),args,symbols); + return symbols->create_function(std::string(i1->begin,i1->end),args); } catch(formula_error& e) { throw formula_error(e.type, tokens_to_string(function_call_begin, function_call_end), *i1->filename, i1->line_number); diff --git a/src/formula/function.cpp b/src/formula/function.cpp index 0580a7b5dff..c9ae22344a9 100644 --- a/src/formula/function.cpp +++ b/src/formula/function.cpp @@ -56,7 +56,7 @@ std::string function_expression::str() const return s.str(); } -namespace { +namespace builtins { class debug_function : public function_expression { public: @@ -1456,7 +1456,34 @@ private: } }; -} +} // namespace builtins + +namespace actions { + +class safe_call_function : public function_expression { +public: + explicit safe_call_function(const args_list& args) + : function_expression("safe_call", args, 2, 2) {} +private: + variant execute(const formula_callable& variables, formula_debugger *fdb) const { + const variant main = args()[0]->evaluate(variables, fdb); + const expression_ptr backup_formula = args()[1]; + + return variant(new safe_call_callable(main, backup_formula)); + } +}; + +class set_var_function : public function_expression { +public: + explicit set_var_function(const args_list& args) + : function_expression("set_var", args, 2, 2) {} +private: + variant execute(const formula_callable& variables, formula_debugger *fdb) const { + return variant(new set_var_callable(args()[0]->evaluate(variables, add_debug_info(fdb, 0, "set_var:key")).as_string(), args()[1]->evaluate(variables, add_debug_info(fdb, 1, "set_var:value")))); + } +}; + +} // namespace actions variant key_value_pair::get_value(const std::string& key) const { @@ -1535,6 +1562,12 @@ function_expression_ptr user_formula_function::generate_function_expression(cons return function_expression_ptr(new formula_function_expression(name_, args, formula_, precondition_, args_)); } +function_symbol_table::function_symbol_table(function_symbol_table* parent) : parent(parent) {} + +function_symbol_table::~function_symbol_table() { + if(parent) delete parent; +} + void function_symbol_table::add_function(const std::string& name, formula_function_ptr fcn) { custom_formulas_[name] = fcn; @@ -1547,26 +1580,36 @@ expression_ptr function_symbol_table::create_function(const std::string& fn, con return i->second->generate_function_expression(args); } - return expression_ptr(); + expression_ptr res((parent ? parent : get_builtins())->create_function(fn, args)); + if(res) { + return res; + } + + throw formula_error("Unknown function: " + fn, "", "", 0); } -std::vector function_symbol_table::get_function_names() const +std::set function_symbol_table::get_function_names() const { - std::vector res; + std::set res; + if(parent) { + res = parent->get_function_names(); + } else if(this != get_builtins()) { + res = get_builtins()->get_function_names(); + } for(functions_map::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); ++iter ) { - res.push_back((*iter).first); + res.insert((*iter).first); } return res; } -namespace { +#define FUNCTION(name) functions_table.add_function(#name, \ + formula_function_ptr(new builtin_formula_function(#name))) -function_symbol_table& get_functions_map() { +function_symbol_table* function_symbol_table::get_builtins() { static function_symbol_table functions_table; if(functions_table.empty()) { -#define FUNCTION(name) functions_table.add_function(#name, \ - formula_function_ptr(new builtin_formula_function(#name))) + using namespace builtins; FUNCTION(debug); FUNCTION(dir); FUNCTION(if); @@ -1627,36 +1670,16 @@ function_symbol_table& get_functions_map() { FUNCTION(pi); FUNCTION(hypot); FUNCTION(type); -#undef FUNCTION } - return functions_table; -} - -} - -expression_ptr create_function(const std::string& fn, - const std::vector& args, - const function_symbol_table* symbols) -{ - if(symbols) { - expression_ptr res(symbols->create_function(fn, args)); - if(res) { - return res; - } - } - - expression_ptr res(get_functions_map().create_function(fn, args)); - if(!res) { - throw formula_error("Unknown function: " + fn, "", "", 0); - } - - return res; -} - -std::vector builtin_function_names() -{ - return get_functions_map().get_function_names(); + return &functions_table; +} + +action_function_symbol_table::action_function_symbol_table() { + using namespace actions; + function_symbol_table& functions_table = *this; + FUNCTION(safe_call); + FUNCTION(set_var); } } diff --git a/src/formula/function.hpp b/src/formula/function.hpp index 55e02730c75..62e6bd7fd18 100644 --- a/src/formula/function.hpp +++ b/src/formula/function.hpp @@ -19,6 +19,8 @@ #include "formula/formula.hpp" #include "formula/callable.hpp" +#include + namespace game_logic { class formula_expression { @@ -134,19 +136,22 @@ typedef std::shared_ptr formula_function_ptr; typedef std::map functions_map; class function_symbol_table { + function_symbol_table* parent = nullptr; functions_map custom_formulas_; public: + explicit function_symbol_table(function_symbol_table* parent = nullptr); + ~function_symbol_table(); void add_function(const std::string& name, formula_function_ptr fcn); expression_ptr create_function(const std::string& fn, const std::vector& args) const; - std::vector get_function_names() const; + std::set get_function_names() const; bool empty() {return custom_formulas_.empty();} + static function_symbol_table* get_builtins(); }; -expression_ptr create_function(const std::string& fn, - const std::vector& args, - const function_symbol_table* symbols); -std::vector builtin_function_names(); - +class action_function_symbol_table : public function_symbol_table { +public: + action_function_symbol_table(); +}; class wrapper_formula : public formula_expression { public: