00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "formula_debugger.hpp"
00023 #include "formula.hpp"
00024 #include "formula_function.hpp"
00025 #include "game_display.hpp"
00026 #include "log.hpp"
00027 #include "resources.hpp"
00028 #include "gui/dialogs/formula_debugger.hpp"
00029 #include "gui/widgets/settings.hpp"
00030
00031 #include <boost/lexical_cast.hpp>
00032
00033 static lg::log_domain log_formula_debugger("ai/debug/formula");
00034 #define DBG_FDB LOG_STREAM(debug, log_formula_debugger)
00035 #define LOG_FDB LOG_STREAM(info, log_formula_debugger)
00036 #define WRN_FDB LOG_STREAM(warn, log_formula_debugger)
00037 #define ERR_FDB LOG_STREAM(err, log_formula_debugger)
00038
00039 namespace game_logic {
00040
00041
00042 debug_info::debug_info(int arg_number, int counter, int level, const std::string &name, const std::string &str, const variant &value, bool evaluated)
00043 : arg_number_(arg_number), counter_(counter), level_(level), name_(name), str_(str), value_(value), evaluated_(evaluated)
00044 {
00045 }
00046
00047
00048 debug_info::~debug_info()
00049 {
00050 }
00051
00052
00053 int debug_info::level() const
00054 {
00055 return level_;
00056 }
00057
00058 const std::string& debug_info::name() const
00059 {
00060 return name_;
00061 }
00062
00063
00064 int debug_info::counter() const
00065 {
00066 return counter_;
00067 }
00068
00069
00070 const variant& debug_info::value() const
00071 {
00072 return value_;
00073 }
00074
00075
00076 void debug_info::set_value(const variant &value)
00077 {
00078 value_ = value;
00079 }
00080
00081
00082 bool debug_info::evaluated() const
00083 {
00084 return evaluated_;
00085 }
00086
00087
00088 void debug_info::set_evaluated(bool evaluated)
00089 {
00090 evaluated_ = evaluated;
00091 }
00092
00093
00094 const std::string& debug_info::str() const
00095 {
00096 return str_;
00097 }
00098
00099
00100 formula_debugger::formula_debugger()
00101 : call_stack_(), counter_(0), current_breakpoint_(), breakpoints_(), execution_trace_(),arg_number_extra_debug_info(-1), f_name_extra_debug_info("")
00102 {
00103 add_breakpoint_step_into();
00104 add_breakpoint_continue_to_end();
00105 }
00106
00107
00108 formula_debugger::~formula_debugger()
00109 {
00110 }
00111
00112
00113 static void msg(const char *act, debug_info &i, const char *to="", const char *result = "")
00114 {
00115 DBG_FDB << "#" << i.counter() << act << std::endl <<" \""<< i.name().c_str() << "\"='" << i.str().c_str() << "' " << to << result << std::endl;
00116 }
00117
00118
00119 void formula_debugger::add_debug_info(int arg_number, const char *f_name)
00120 {
00121 arg_number_extra_debug_info = arg_number;
00122 f_name_extra_debug_info = f_name;
00123 }
00124
00125
00126 const std::deque<debug_info>& formula_debugger::get_call_stack() const
00127 {
00128 return call_stack_;
00129 }
00130
00131
00132 const breakpoint_ptr formula_debugger::get_current_breakpoint() const
00133 {
00134 return current_breakpoint_;
00135 }
00136
00137 const std::deque<debug_info>& formula_debugger::get_execution_trace() const
00138 {
00139 return execution_trace_;
00140 }
00141
00142 void formula_debugger::check_breakpoints()
00143 {
00144 for( std::deque< breakpoint_ptr >::iterator b = breakpoints_.begin(); b!= breakpoints_.end(); ++b) {
00145 if ((*b)->is_break_now()){
00146 current_breakpoint_ = (*b);
00147 show_gui();
00148 current_breakpoint_ = breakpoint_ptr();
00149 if ((*b)->is_one_time_only()) {
00150 breakpoints_.erase(b);
00151 }
00152 break;
00153 }
00154 }
00155 }
00156
00157 void formula_debugger::show_gui()
00158 {
00159 if (resources::screen == NULL) {
00160 WRN_FDB << "do not showing debug window due to NULL gui" << std::endl;
00161 return;
00162 }
00163 if (gui2::new_widgets) {
00164 gui2::tformula_debugger debug_dialog(*this);
00165 debug_dialog.show(resources::screen->video());
00166 } else {
00167 WRN_FDB << "do not showing debug window due to disabled --new-widgets"<< std::endl;
00168 }
00169 }
00170
00171 void formula_debugger::call_stack_push(const std::string &str)
00172 {
00173 call_stack_.push_back(debug_info(arg_number_extra_debug_info,counter_++,call_stack_.size(),f_name_extra_debug_info,str,variant(),false));
00174 arg_number_extra_debug_info = -1;
00175 f_name_extra_debug_info = "";
00176 execution_trace_.push_back(call_stack_.back());
00177 }
00178
00179
00180 void formula_debugger::call_stack_pop()
00181 {
00182 execution_trace_.push_back(call_stack_.back());
00183 call_stack_.pop_back();
00184 }
00185
00186
00187 void formula_debugger::call_stack_set_evaluated(bool evaluated)
00188 {
00189 call_stack_.back().set_evaluated(evaluated);
00190 }
00191
00192 void formula_debugger::call_stack_set_value(const variant &v)
00193 {
00194 call_stack_.back().set_value(v);
00195 }
00196
00197 variant formula_debugger::evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables)
00198 {
00199 call_stack_push(expression.str());
00200 check_breakpoints();
00201 msg(" evaluating expression: ",call_stack_.back());
00202 variant v = expression.execute(variables,this);
00203 call_stack_set_value(v);
00204 call_stack_set_evaluated(true);
00205 msg(" evaluated expression: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
00206 check_breakpoints();
00207 call_stack_pop();
00208 return v;
00209 }
00210
00211
00212 variant formula_debugger::evaluate_formula_callback(const formula &f, const formula_callable &variables)
00213 {
00214 call_stack_push(f.str());
00215 check_breakpoints();
00216 msg(" evaluating formula: ",call_stack_.back());
00217 variant v = f.execute(variables,this);
00218 call_stack_set_value(v);
00219 call_stack_set_evaluated(true);
00220 msg(" evaluated formula: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
00221 check_breakpoints();
00222 call_stack_pop();
00223 return v;
00224 }
00225
00226
00227 variant formula_debugger::evaluate_formula_callback(const formula &f)
00228 {
00229 call_stack_push(f.str());
00230 check_breakpoints();
00231 msg(" evaluating formula without variables: ",call_stack_.back());
00232 variant v = f.execute(this);
00233 call_stack_set_value(v);
00234 call_stack_set_evaluated(true);
00235 msg(" evaluated formula without variables: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
00236 check_breakpoints();
00237 call_stack_pop();
00238 return v;
00239 }
00240
00241
00242 base_breakpoint::base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only)
00243 : fdb_(fdb), name_(name), one_time_only_(one_time_only)
00244 {
00245
00246 }
00247
00248
00249 base_breakpoint::~base_breakpoint()
00250 {
00251 }
00252
00253
00254 bool base_breakpoint::is_one_time_only() const
00255 {
00256 return one_time_only_;
00257 }
00258
00259
00260 const std::string& base_breakpoint::name() const
00261 {
00262 return name_;
00263 }
00264
00265 class end_breakpoint : public base_breakpoint {
00266 public:
00267 end_breakpoint(formula_debugger &fdb)
00268 : base_breakpoint(fdb,"End", true)
00269 {
00270 }
00271
00272 virtual ~end_breakpoint()
00273 {
00274 }
00275
00276 virtual bool is_break_now() const
00277 {
00278 const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
00279 if ((call_stack.size() == 1) && (call_stack[0].evaluated()) ) {
00280 return true;
00281 }
00282 return false;
00283 }
00284 };
00285
00286
00287 class step_in_breakpoint : public base_breakpoint {
00288 public:
00289 step_in_breakpoint(formula_debugger &fdb)
00290 : base_breakpoint(fdb,"Step",true)
00291 {
00292 }
00293
00294 virtual ~step_in_breakpoint()
00295 {
00296 }
00297
00298 virtual bool is_break_now() const
00299 {
00300 const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
00301 if (call_stack.empty() || call_stack.back().evaluated()) {
00302 return false;
00303 }
00304
00305 return true;
00306 }
00307 };
00308
00309
00310 class step_out_breakpoint : public base_breakpoint {
00311 public:
00312 step_out_breakpoint(formula_debugger &fdb)
00313 : base_breakpoint(fdb,"Step out",true), level_(fdb.get_call_stack().size()-1)
00314 {
00315 }
00316
00317 virtual ~step_out_breakpoint()
00318 {
00319 }
00320
00321 virtual bool is_break_now() const
00322 {
00323 const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
00324 if (call_stack.empty() || call_stack.back().evaluated()) {
00325 return false;
00326 }
00327
00328 if (call_stack.size() == level_) {
00329 return true;
00330 }
00331 return false;
00332 }
00333 private:
00334 size_t level_;
00335 };
00336
00337
00338 class next_breakpoint : public base_breakpoint {
00339 public:
00340 next_breakpoint(formula_debugger &fdb)
00341 : base_breakpoint(fdb,"Next",true), level_(fdb.get_call_stack().size())
00342 {
00343 }
00344
00345 virtual ~next_breakpoint()
00346 {
00347 }
00348
00349 virtual bool is_break_now() const
00350 {
00351 const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
00352 if (call_stack.empty() || call_stack.back().evaluated()) {
00353 return false;
00354 }
00355 if (call_stack.size() == level_) {
00356 return true;
00357 }
00358 return false;
00359 }
00360 private:
00361 size_t level_;
00362 };
00363
00364
00365 void formula_debugger::add_breakpoint_continue_to_end()
00366 {
00367 breakpoints_.push_back(breakpoint_ptr(new end_breakpoint(*this)));
00368 LOG_FDB << "added 'end' breakpoint"<< std::endl;
00369 }
00370
00371
00372 void formula_debugger::add_breakpoint_step_into()
00373 {
00374 breakpoints_.push_back(breakpoint_ptr(new step_in_breakpoint(*this)));
00375 LOG_FDB << "added 'step into' breakpoint"<< std::endl;
00376 }
00377
00378
00379 void formula_debugger::add_breakpoint_step_out()
00380 {
00381 breakpoints_.push_back(breakpoint_ptr(new step_out_breakpoint(*this)));
00382 LOG_FDB << "added 'step out' breakpoint"<< std::endl;
00383 }
00384
00385
00386 void formula_debugger::add_breakpoint_next()
00387 {
00388 breakpoints_.push_back(breakpoint_ptr(new next_breakpoint(*this)));
00389 LOG_FDB << "added 'next' breakpoint"<< std::endl;
00390 }
00391
00392
00393 }