The Battle for Wesnoth  1.17.0-dev
debugger.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2021
3  by Yurii Chernyi <terraninfo@terraninfo.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 /**
17  * @file
18  * Formula debugger - implementation
19  * */
20 
21 
22 #include "formula/debugger.hpp"
23 #include "formula/formula.hpp"
24 #include "formula/function.hpp"
25 #include "game_display.hpp"
26 #include "log.hpp"
28 #include "gui/widgets/settings.hpp"
29 
30 static lg::log_domain log_formula_debugger("scripting/formula/debug");
31 #define DBG_FDB LOG_STREAM(debug, log_formula_debugger)
32 #define LOG_FDB LOG_STREAM(info, log_formula_debugger)
33 #define WRN_FDB LOG_STREAM(warn, log_formula_debugger)
34 #define ERR_FDB LOG_STREAM(err, log_formula_debugger)
35 
36 namespace wfl {
37 
38 
39 debug_info::debug_info(int arg_number, int counter, int level, const std::string &name, const std::string &str, const variant &value, bool evaluated)
40  : arg_number_(arg_number), counter_(counter), level_(level), name_(name), str_(str), value_(value), evaluated_(evaluated)
41 {
42 }
43 
44 
46 {
47 }
48 
49 
50 int debug_info::level() const
51 {
52  return level_;
53 }
54 
55 const std::string& debug_info::name() const
56 {
57  return name_;
58 }
59 
60 
62 {
63  return counter_;
64 }
65 
66 
67 const variant& debug_info::value() const
68 {
69  return value_;
70 }
71 
72 
74 {
75  value_ = value;
76 }
77 
78 
80 {
81  return evaluated_;
82 }
83 
84 
86 {
88 }
89 
90 
91 const std::string& debug_info::str() const
92 {
93  return str_;
94 }
95 
96 
98  : call_stack_(), counter_(0), current_breakpoint_(), breakpoints_(), execution_trace_(),arg_number_extra_debug_info(-1), f_name_extra_debug_info("")
99 {
102 }
103 
104 
106 {
107 }
108 
109 
110 static void msg(const char *act, debug_info &i, const char *to="", const char *result = "")
111 {
112  DBG_FDB << "#" << i.counter() << act << std::endl <<" \""<< i.name() << "\"='" << i.str() << "' " << to << result << std::endl;
113 }
114 
115 
116 void formula_debugger::add_debug_info(int arg_number, const std::string& f_name)
117 {
118  arg_number_extra_debug_info = arg_number;
119  f_name_extra_debug_info = f_name;
120 }
121 
122 
123 const std::list<debug_info>& formula_debugger::get_call_stack() const
124 {
125  return call_stack_;
126 }
127 
128 
130 {
131  return current_breakpoint_;
132 }
133 
134 const std::list<debug_info>& formula_debugger::get_execution_trace() const
135 {
136  return execution_trace_;
137 }
138 
140 {
141  for(std::list<breakpoint_ptr>::iterator b = breakpoints_.begin(); b != breakpoints_.end(); ++b) {
142  if ((*b)->is_break_now()){
143  current_breakpoint_ = (*b);
144  show_gui();
146  if ((*b)->is_one_time_only()) {
147  b = breakpoints_.erase(b);
148  }
149  break;
150  }
151  }
152 }
153 
155 {
156  if (game_display::get_singleton() == nullptr) {
157  WRN_FDB << "skipping WFL debug window due to nullptr gui" << std::endl;
158  return;
159  }
160  if (game_config::debug) {
161  gui2::dialogs::formula_debugger::display(*this);
162  } else {
163  WRN_FDB << "skipping WFL debug window because :debug is not enabled"<< std::endl;
164  }
165 }
166 
167 void formula_debugger::call_stack_push(const std::string &str)
168 {
172  execution_trace_.push_back(call_stack_.back());
173 }
174 
175 
177 {
178  execution_trace_.push_back(call_stack_.back());
179  call_stack_.pop_back();
180 }
181 
182 
184 {
185  call_stack_.back().set_evaluated(evaluated);
186 }
187 
189 {
190  call_stack_.back().set_value(v);
191 }
192 
194 {
195  call_stack_push(expression.str());
197  msg(" evaluating expression: ",call_stack_.back());
198  variant v = expression.execute(variables,this);
201  msg(" evaluated expression: ",call_stack_.back()," to ",v.to_debug_string(true).c_str());
203  call_stack_pop();
204  return v;
205 }
206 
207 
209 {
210  call_stack_push(f.str());
212  msg(" evaluating formula: ",call_stack_.back());
213  variant v = f.execute(variables,this);
216  msg(" evaluated formula: ",call_stack_.back()," to ",v.to_debug_string(true).c_str());
218  call_stack_pop();
219  return v;
220 }
221 
222 
224 {
225  call_stack_push(f.str());
227  msg(" evaluating formula without variables: ",call_stack_.back());
228  variant v = f.execute(this);
231  msg(" evaluated formula without variables: ",call_stack_.back()," to ",v.to_debug_string(true).c_str());
233  call_stack_pop();
234  return v;
235 }
236 
237 
238 base_breakpoint::base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only)
239  : fdb_(fdb), name_(name), one_time_only_(one_time_only)
240 {
241 
242 }
243 
244 
246 {
247 }
248 
249 
251 {
252  return one_time_only_;
253 }
254 
255 
256 const std::string& base_breakpoint::name() const
257 {
258  return name_;
259 }
260 
262 public:
264  : base_breakpoint(fdb,"End", true)
265  {
266  }
267 
268  virtual ~end_breakpoint()
269  {
270  }
271 
272  virtual bool is_break_now() const
273  {
274  const std::list<debug_info> &call_stack = fdb_.get_call_stack();
275  if ((call_stack.size() == 1) && (call_stack.front().evaluated()) ) {
276  return true;
277  }
278  return false;
279  }
280 };
281 
282 
284 public:
286  : base_breakpoint(fdb,"Step",true)
287  {
288  }
289 
291  {
292  }
293 
294  virtual bool is_break_now() const
295  {
296  const std::list<debug_info> &call_stack = fdb_.get_call_stack();
297  if (call_stack.empty() || call_stack.back().evaluated()) {
298  return false;
299  }
300 
301  return true;
302  }
303 };
304 
305 
307 public:
309  : base_breakpoint(fdb,"Step out",true), level_(fdb.get_call_stack().size()-1)
310  {
311  }
312 
314  {
315  }
316 
317  virtual bool is_break_now() const
318  {
319  const std::list<debug_info> &call_stack = fdb_.get_call_stack();
320  if (call_stack.empty() || call_stack.back().evaluated()) {
321  return false;
322  }
323 
324  if (call_stack.size() == level_) {
325  return true;
326  }
327  return false;
328  }
329 private:
330  std::size_t level_;
331 };
332 
333 
335 public:
337  : base_breakpoint(fdb,"Next",true), level_(fdb.get_call_stack().size())
338  {
339  }
340 
342  {
343  }
344 
345  virtual bool is_break_now() const
346  {
347  const std::list<debug_info> &call_stack = fdb_.get_call_stack();
348  if (call_stack.empty() || call_stack.back().evaluated()) {
349  return false;
350  }
351  if (call_stack.size() == level_) {
352  return true;
353  }
354  return false;
355  }
356 private:
357  std::size_t level_;
358 };
359 
360 
362 {
363  breakpoints_.emplace_back(new end_breakpoint(*this));
364  LOG_FDB << "added 'end' breakpoint"<< std::endl;
365 }
366 
367 
369 {
370  breakpoints_.emplace_back(new step_in_breakpoint(*this));
371  LOG_FDB << "added 'step into' breakpoint"<< std::endl;
372 }
373 
374 
376 {
377  breakpoints_.emplace_back(new step_out_breakpoint(*this));
378  LOG_FDB << "added 'step out' breakpoint"<< std::endl;
379 }
380 
381 
383 {
384  breakpoints_.emplace_back(new next_breakpoint(*this));
385  LOG_FDB << "added 'next' breakpoint"<< std::endl;
386 }
387 
388 
389 } // end of namespace wfl
int level() const
Definition: debugger.cpp:50
virtual ~next_breakpoint()
Definition: debugger.cpp:341
virtual ~step_in_breakpoint()
Definition: debugger.cpp:290
virtual bool is_break_now() const
Definition: debugger.cpp:317
virtual std::string str() const =0
void add_debug_info(int arg_number, const std::string &f_name)
Definition: debugger.cpp:116
void add_breakpoint_step_out()
Definition: debugger.cpp:375
Formula AI debugger.
void call_stack_push(const std::string &str)
Definition: debugger.cpp:167
std::list< debug_info > call_stack_
Definition: debugger.hpp:145
debug_info(int arg_number, int counter, int level, const std::string &name, const std::string &str, const variant &value, bool evaluated)
Definition: debugger.cpp:39
const std::string & str() const
Definition: formula.hpp:73
variant value_
Definition: debugger.hpp:54
std::list< breakpoint_ptr > breakpoints_
Definition: debugger.hpp:148
void set_evaluated(bool evaluated)
Definition: debugger.cpp:85
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
std::size_t level_
Definition: debugger.cpp:357
formula_debugger & fdb_
Definition: debugger.hpp:67
const std::string & name() const
Definition: debugger.cpp:256
std::shared_ptr< base_breakpoint > breakpoint_ptr
#define b
breakpoint_ptr current_breakpoint_
Definition: debugger.hpp:147
const breakpoint_ptr get_current_breakpoint() const
Definition: debugger.cpp:129
virtual ~base_breakpoint()
Definition: debugger.cpp:245
variant evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables)
Definition: debugger.cpp:193
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
This file contains the settings handling of the widget library.
std::string f_name_extra_debug_info
Definition: debugger.hpp:151
#define WRN_FDB
Definition: debugger.cpp:33
step_in_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:285
virtual ~end_breakpoint()
Definition: debugger.cpp:268
virtual ~step_out_breakpoint()
Definition: debugger.cpp:313
void set_value(const variant &value)
Definition: debugger.cpp:73
virtual ~debug_info()
Definition: debugger.cpp:45
const variant & value() const
Definition: debugger.cpp:67
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:47
static lg::log_domain log_formula_debugger("scripting/formula/debug")
int counter() const
Definition: debugger.cpp:61
std::list< debug_info > execution_trace_
Definition: debugger.hpp:149
std::string str_
Definition: debugger.hpp:53
std::string name_
Definition: debugger.hpp:52
variant evaluate_formula_callback(const formula &f, const formula_callable &variables)
Definition: debugger.cpp:208
std::string name_
Definition: debugger.hpp:68
std::size_t i
Definition: function.cpp:967
virtual bool is_break_now() const
Definition: debugger.cpp:272
virtual bool is_break_now() const
Definition: debugger.cpp:294
next_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:336
#define LOG_FDB
Definition: debugger.cpp:32
void call_stack_set_value(const variant &v)
Definition: debugger.cpp:188
bool evaluated() const
Definition: debugger.cpp:79
#define DBG_FDB
Definition: debugger.cpp:31
const bool & debug
bool is_one_time_only() const
Definition: debugger.cpp:250
virtual ~formula_debugger()
Definition: debugger.cpp:105
void add_breakpoint_continue_to_end()
Definition: debugger.cpp:361
const std::list< debug_info > & get_call_stack() const
Definition: debugger.cpp:123
#define f
Definition: contexts.hpp:44
const std::string & str() const
Definition: debugger.cpp:91
const std::string & name() const
Definition: debugger.cpp:55
Standard logging facilities (interface).
base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only)
Definition: debugger.cpp:238
variant execute(const formula_callable &variables, formula_debugger *fdb=nullptr) const
Definition: formula.cpp:260
void add_breakpoint_step_into()
Definition: debugger.cpp:368
virtual bool is_break_now() const
Definition: debugger.cpp:345
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
step_out_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:308
void call_stack_set_evaluated(bool evaluated)
Definition: debugger.cpp:183
const std::list< debug_info > & get_execution_trace() const
Definition: debugger.cpp:134
virtual variant execute(const formula_callable &variables, formula_debugger *fdb=nullptr) const =0
static game_display * get_singleton()
end_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:263