The Battle for Wesnoth  1.17.23+dev
debugger.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2023
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 
73 void debug_info::set_value(const variant &value)
74 {
75  value_ = value;
76 }
77 
78 
80 {
81  return evaluated_;
82 }
83 
84 
85 void debug_info::set_evaluated(bool evaluated)
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;
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";
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";
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";
365 }
366 
367 
369 {
370  breakpoints_.emplace_back(new step_in_breakpoint(*this));
371  LOG_FDB << "added 'step into' breakpoint";
372 }
373 
374 
376 {
377  breakpoints_.emplace_back(new step_out_breakpoint(*this));
378  LOG_FDB << "added 'step out' breakpoint";
379 }
380 
381 
383 {
384  breakpoints_.emplace_back(new next_breakpoint(*this));
385  LOG_FDB << "added 'next' breakpoint";
386 }
387 
388 
389 } // end of namespace wfl
static game_display * get_singleton()
std::string name_
Definition: debugger.hpp:68
formula_debugger & fdb_
Definition: debugger.hpp:67
virtual ~base_breakpoint()
Definition: debugger.cpp:245
const std::string & name() const
Definition: debugger.cpp:256
base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only)
Definition: debugger.cpp:238
bool is_one_time_only() const
Definition: debugger.cpp:250
variant value_
Definition: debugger.hpp:54
bool evaluated() const
Definition: debugger.cpp:79
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 variant & value() const
Definition: debugger.cpp:67
virtual ~debug_info()
Definition: debugger.cpp:45
std::string name_
Definition: debugger.hpp:52
int level() const
Definition: debugger.cpp:50
void set_evaluated(bool evaluated)
Definition: debugger.cpp:85
const std::string & name() const
Definition: debugger.cpp:55
std::string str_
Definition: debugger.hpp:53
const std::string & str() const
Definition: debugger.cpp:91
void set_value(const variant &value)
Definition: debugger.cpp:73
int counter() const
Definition: debugger.cpp:61
end_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:263
virtual ~end_breakpoint()
Definition: debugger.cpp:268
virtual bool is_break_now() const
Definition: debugger.cpp:272
const std::list< debug_info > & get_execution_trace() const
Definition: debugger.cpp:134
void add_debug_info(int arg_number, const std::string &f_name)
Definition: debugger.cpp:116
std::list< debug_info > call_stack_
Definition: debugger.hpp:145
std::string f_name_extra_debug_info
Definition: debugger.hpp:151
void add_breakpoint_step_into()
Definition: debugger.cpp:368
virtual ~formula_debugger()
Definition: debugger.cpp:105
breakpoint_ptr current_breakpoint_
Definition: debugger.hpp:147
std::list< debug_info > execution_trace_
Definition: debugger.hpp:149
void call_stack_push(const std::string &str)
Definition: debugger.cpp:167
variant evaluate_formula_callback(const formula &f, const formula_callable &variables)
Definition: debugger.cpp:208
void add_breakpoint_continue_to_end()
Definition: debugger.cpp:361
variant evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables)
Definition: debugger.cpp:193
void call_stack_set_value(const variant &v)
Definition: debugger.cpp:188
void add_breakpoint_step_out()
Definition: debugger.cpp:375
const std::list< debug_info > & get_call_stack() const
Definition: debugger.cpp:123
void call_stack_set_evaluated(bool evaluated)
Definition: debugger.cpp:183
std::list< breakpoint_ptr > breakpoints_
Definition: debugger.hpp:148
const breakpoint_ptr get_current_breakpoint() const
Definition: debugger.cpp:129
virtual std::string str() const =0
virtual variant execute(const formula_callable &variables, formula_debugger *fdb=nullptr) const =0
virtual ~next_breakpoint()
Definition: debugger.cpp:341
virtual bool is_break_now() const
Definition: debugger.cpp:345
std::size_t level_
Definition: debugger.cpp:357
next_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:336
virtual ~step_in_breakpoint()
Definition: debugger.cpp:290
virtual bool is_break_now() const
Definition: debugger.cpp:294
step_in_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:285
step_out_breakpoint(formula_debugger &fdb)
Definition: debugger.cpp:308
virtual bool is_break_now() const
Definition: debugger.cpp:317
virtual ~step_out_breakpoint()
Definition: debugger.cpp:313
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:646
#define LOG_FDB
Definition: debugger.cpp:32
static lg::log_domain log_formula_debugger("scripting/formula/debug")
#define WRN_FDB
Definition: debugger.cpp:33
#define DBG_FDB
Definition: debugger.cpp:31
Formula AI debugger.
std::size_t i
Definition: function.cpp:968
Standard logging facilities (interface).
const bool & debug
Definition: game_config.cpp:91
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Definition: contexts.hpp:44
std::shared_ptr< base_breakpoint > breakpoint_ptr
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
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:48
This file contains the settings handling of the widget library.
#define f
#define b