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