1 2 /* 3 Copyright (C) 2008 - 2018 by David White <dave@whitevine.net> 4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/ 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY. 12 13 See the COPYING file for more details. 14 */ 15 16 #pragma once 17 18 #include "formula/callable.hpp" 19 #include "formula/formula.hpp" 20 21 #include <set> 22 #include <string> 23 24 namespace wfl 25 { 26 /** Helper macro to declare an associated class for a WFL function. */ 27 #define DEFINE_WFL_FUNCTION(name, min_args, max_args) \ 28 class name##_function : public function_expression \ 29 { \ 30 public: \ 31 explicit name##_function(const args_list& args) \ 32 : function_expression(#name, args, min_args, max_args) \ 33 { \ 34 } \ 35 \ 36 private: \ 37 variant execute(const formula_callable& variables, formula_debugger* fdb) const; \ 38 }; \ 39 \ 40 variant name##_function::execute(const formula_callable& variables, formula_debugger* fdb) const 41 42 43 /** 44 * Declares a function `name` in the local function table `functions_table`. 45 * The function must be defined by a `name_function` class which is accessible in the current scope. 46 */ 47 #define DECLARE_WFL_FUNCTION(name) \ 48 functions_table.add_function(#name, std::make_shared<builtin_formula_function<name##_function>>(#name)) 49 50 /** 51 * Provides debugging information for error messages. 52 */ 53 struct call_stack_manager 54 { 55 explicit call_stack_manager(const std::string& str); 56 call_stack_manager(const call_stack_manager&) = delete; 57 call_stack_manager& operator=(const call_stack_manager&) = delete; 58 ~call_stack_manager(); 59 60 static std::string get(); 61 }; 62 63 class formula_expression 64 { 65 public: formula_expression(const std::string & name="")66 explicit formula_expression(const std::string& name = "") 67 : name_(name) 68 { 69 } 70 ~formula_expression()71 virtual ~formula_expression() 72 { 73 } 74 evaluate(const formula_callable & variables,formula_debugger * fdb=nullptr) const75 variant evaluate(const formula_callable& variables, formula_debugger* fdb = nullptr) const 76 { 77 call_stack_manager manager(name_); 78 79 if(fdb != nullptr) { 80 return evaluate_arg_callback(*fdb, *this, variables); 81 } else { 82 return execute(variables, fdb); 83 } 84 } 85 get_name() const86 std::string get_name() const 87 { 88 return name_; 89 } 90 91 virtual std::string str() const = 0; 92 93 private: 94 virtual variant execute(const formula_callable& variables, formula_debugger* fdb = nullptr) const = 0; 95 96 const std::string name_; 97 friend class formula_debugger; 98 }; 99 100 typedef std::shared_ptr<formula_expression> expression_ptr; 101 102 class function_expression : public formula_expression 103 { 104 public: 105 typedef std::vector<expression_ptr> args_list; 106 function_expression(const std::string & name,const args_list & args,int min_args=-1,int max_args=-1)107 explicit function_expression(const std::string& name, const args_list& args, int min_args = -1, int max_args = -1) 108 : formula_expression(name) 109 , args_(args) 110 { 111 if(min_args >= 0 && args_.size() < static_cast<size_t>(min_args)) { 112 throw formula_error("Too few arguments", "", "", 0); 113 } 114 115 if(max_args >= 0 && args_.size() > static_cast<size_t>(max_args)) { 116 throw formula_error("Too many arguments", "", "", 0); 117 } 118 } 119 120 virtual std::string str() const; 121 122 protected: args() const123 const args_list& args() const 124 { 125 return args_; 126 } 127 128 private: 129 args_list args_; 130 }; 131 132 class key_value_pair : public formula_callable 133 { 134 public: key_value_pair(const variant & key,const variant & value)135 explicit key_value_pair(const variant& key, const variant& value) 136 : key_(key) 137 , value_(value) 138 { 139 } 140 141 void serialize_to_string(std::string& str) const override; 142 143 private: 144 variant key_; 145 variant value_; 146 147 variant get_value(const std::string& key) const override; 148 149 void get_inputs(formula_input_vector& inputs) const override; 150 }; 151 152 class formula_function_expression : public function_expression 153 { 154 public: 155 explicit formula_function_expression(const std::string& name, 156 const args_list& args, 157 const_formula_ptr formula, 158 const_formula_ptr precondition, 159 const std::vector<std::string>& arg_names); 160 161 private: 162 variant execute(const formula_callable& variables, formula_debugger* fdb) const; 163 164 const_formula_ptr formula_; 165 const_formula_ptr precondition_; 166 167 std::vector<std::string> arg_names_; 168 169 int star_arg_; 170 }; 171 172 typedef std::shared_ptr<function_expression> function_expression_ptr; 173 174 class formula_function 175 { 176 public: formula_function(const std::string name)177 formula_function(const std::string name) 178 : name_(name) 179 { 180 } 181 182 virtual function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const = 0; 183 ~formula_function()184 virtual ~formula_function() 185 { 186 } 187 188 protected: 189 std::string name_; 190 }; 191 192 class user_formula_function : public formula_function 193 { 194 public: user_formula_function(const std::string & name,const_formula_ptr formula,const_formula_ptr precondition,const std::vector<std::string> & args)195 user_formula_function(const std::string& name, 196 const_formula_ptr formula, 197 const_formula_ptr precondition, 198 const std::vector<std::string>& args) 199 : formula_function(name) 200 , formula_(formula) 201 , precondition_(precondition) 202 , args_(args) 203 { 204 } 205 206 function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const; 207 208 private: 209 const_formula_ptr formula_; 210 const_formula_ptr precondition_; 211 std::vector<std::string> args_; 212 }; 213 214 template<typename T> 215 class builtin_formula_function : public formula_function 216 { 217 public: builtin_formula_function(const std::string & name)218 builtin_formula_function(const std::string& name) 219 : formula_function(name) 220 { 221 } 222 generate_function_expression(const std::vector<expression_ptr> & args) const223 function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const 224 { 225 return std::make_shared<T>(args); 226 } 227 }; 228 229 typedef std::shared_ptr<formula_function> formula_function_ptr; 230 typedef std::map<std::string, formula_function_ptr> functions_map; 231 232 class function_symbol_table 233 { 234 public: 235 explicit function_symbol_table(std::shared_ptr<function_symbol_table> parent = nullptr); 236 237 void add_function(const std::string& name, formula_function_ptr&& fcn); 238 239 expression_ptr create_function(const std::string& fn, const std::vector<expression_ptr>& args) const; 240 241 std::set<std::string> get_function_names() const; 242 empty() const243 bool empty() const 244 { 245 return custom_formulas_.empty() && (parent == nullptr || parent->empty()); 246 } 247 248 static std::shared_ptr<function_symbol_table> get_builtins(); 249 250 private: 251 std::shared_ptr<function_symbol_table> parent; 252 functions_map custom_formulas_; 253 254 enum builtins_tag_t { builtins_tag }; function_symbol_table(builtins_tag_t)255 function_symbol_table(builtins_tag_t) 256 { 257 } 258 }; 259 260 class action_function_symbol_table : public function_symbol_table 261 { 262 public: 263 action_function_symbol_table(std::shared_ptr<function_symbol_table> parent = nullptr); 264 }; 265 266 class wrapper_formula : public formula_expression 267 { 268 public: wrapper_formula()269 wrapper_formula() 270 : arg_() 271 { 272 } 273 wrapper_formula(expression_ptr arg)274 wrapper_formula(expression_ptr arg) 275 : formula_expression(arg ? arg->get_name() : "") 276 , arg_(arg) 277 { 278 } 279 ~wrapper_formula()280 virtual ~wrapper_formula() 281 { 282 } 283 str() const284 virtual std::string str() const 285 { 286 if(arg_) { 287 return arg_->str(); 288 } else { 289 return ""; 290 } 291 } 292 293 private: execute(const formula_callable & variables,formula_debugger * fdb=nullptr) const294 virtual variant execute(const formula_callable& variables, formula_debugger* fdb = nullptr) const 295 { 296 if(arg_) { 297 return arg_->evaluate(variables, fdb); 298 } else { 299 return variant(); 300 } 301 } 302 303 expression_ptr arg_; 304 }; 305 } // end namespace wfl 306