mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-10 06:02:50 +00:00
393 lines
8.5 KiB
C++
393 lines
8.5 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
|
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License version 2
|
|
or at your option any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file src/formula_debugger.cpp
|
|
* Formula debugger - implementation
|
|
* */
|
|
|
|
|
|
#include "formula_debugger.hpp"
|
|
#include "formula.hpp"
|
|
#include "formula_function.hpp"
|
|
#include "game_display.hpp"
|
|
#include "log.hpp"
|
|
#include "resources.hpp"
|
|
#include "gui/dialogs/formula_debugger.hpp"
|
|
#include "gui/widgets/settings.hpp"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
static lg::log_domain log_formula_debugger("ai/debug/formula");
|
|
#define DBG_FDB LOG_STREAM(debug, log_formula_debugger)
|
|
#define LOG_FDB LOG_STREAM(info, log_formula_debugger)
|
|
#define WRN_FDB LOG_STREAM(warn, log_formula_debugger)
|
|
#define ERR_FDB LOG_STREAM(err, log_formula_debugger)
|
|
|
|
namespace game_logic {
|
|
|
|
|
|
debug_info::debug_info(int arg_number, int counter, int level, const std::string &name, const std::string &str, const variant &value, bool evaluated)
|
|
: arg_number_(arg_number), counter_(counter), level_(level), name_(name), str_(str), value_(value), evaluated_(evaluated)
|
|
{
|
|
}
|
|
|
|
|
|
debug_info::~debug_info()
|
|
{
|
|
}
|
|
|
|
|
|
int debug_info::level() const
|
|
{
|
|
return level_;
|
|
}
|
|
|
|
const std::string& debug_info::name() const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
|
|
int debug_info::counter() const
|
|
{
|
|
return counter_;
|
|
}
|
|
|
|
|
|
const variant& debug_info::value() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
|
|
void debug_info::set_value(const variant &value)
|
|
{
|
|
value_ = value;
|
|
}
|
|
|
|
|
|
bool debug_info::evaluated() const
|
|
{
|
|
return evaluated_;
|
|
}
|
|
|
|
|
|
void debug_info::set_evaluated(bool evaluated)
|
|
{
|
|
evaluated_ = evaluated;
|
|
}
|
|
|
|
|
|
const std::string& debug_info::str() const
|
|
{
|
|
return str_;
|
|
}
|
|
|
|
|
|
formula_debugger::formula_debugger()
|
|
: call_stack_(), counter_(0), current_breakpoint_(), breakpoints_(), execution_trace_(),arg_number_extra_debug_info(-1), f_name_extra_debug_info("")
|
|
{
|
|
add_breakpoint_step_into();
|
|
add_breakpoint_continue_to_end();
|
|
}
|
|
|
|
|
|
formula_debugger::~formula_debugger()
|
|
{
|
|
}
|
|
|
|
|
|
static void msg(const char *act, debug_info &i, const char *to="", const char *result = "")
|
|
{
|
|
DBG_FDB << "#" << i.counter() << act << std::endl <<" \""<< i.name().c_str() << "\"='" << i.str().c_str() << "' " << to << result << std::endl;
|
|
}
|
|
|
|
|
|
void formula_debugger::add_debug_info(int arg_number, const char *f_name)
|
|
{
|
|
arg_number_extra_debug_info = arg_number;
|
|
f_name_extra_debug_info = f_name;
|
|
}
|
|
|
|
|
|
const std::deque<debug_info>& formula_debugger::get_call_stack() const
|
|
{
|
|
return call_stack_;
|
|
}
|
|
|
|
|
|
const breakpoint_ptr formula_debugger::get_current_breakpoint() const
|
|
{
|
|
return current_breakpoint_;
|
|
}
|
|
|
|
const std::deque<debug_info>& formula_debugger::get_execution_trace() const
|
|
{
|
|
return execution_trace_;
|
|
}
|
|
|
|
void formula_debugger::check_breakpoints()
|
|
{
|
|
for( std::deque< breakpoint_ptr >::iterator b = breakpoints_.begin(); b!= breakpoints_.end(); ++b) {
|
|
if ((*b)->is_break_now()){
|
|
current_breakpoint_ = (*b);
|
|
show_gui();
|
|
current_breakpoint_ = breakpoint_ptr();
|
|
if ((*b)->is_one_time_only()) {
|
|
breakpoints_.erase(b);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void formula_debugger::show_gui()
|
|
{
|
|
if (resources::screen == NULL) {
|
|
WRN_FDB << "do not showing debug window due to NULL gui" << std::endl;
|
|
return;
|
|
}
|
|
if (gui2::new_widgets) {
|
|
gui2::tformula_debugger debug_dialog(*this);
|
|
debug_dialog.show(resources::screen->video());
|
|
} else {
|
|
WRN_FDB << "do not showing debug window due to disabled --new-widgets"<< std::endl;
|
|
}
|
|
}
|
|
|
|
void formula_debugger::call_stack_push(const std::string &str)
|
|
{
|
|
call_stack_.push_back(debug_info(arg_number_extra_debug_info,counter_++,call_stack_.size(),f_name_extra_debug_info,str,variant(),false));
|
|
arg_number_extra_debug_info = -1;
|
|
f_name_extra_debug_info = "";
|
|
execution_trace_.push_back(call_stack_.back());
|
|
}
|
|
|
|
|
|
void formula_debugger::call_stack_pop()
|
|
{
|
|
execution_trace_.push_back(call_stack_.back());
|
|
call_stack_.pop_back();
|
|
}
|
|
|
|
|
|
void formula_debugger::call_stack_set_evaluated(bool evaluated)
|
|
{
|
|
call_stack_.back().set_evaluated(evaluated);
|
|
}
|
|
|
|
void formula_debugger::call_stack_set_value(const variant &v)
|
|
{
|
|
call_stack_.back().set_value(v);
|
|
}
|
|
|
|
variant formula_debugger::evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables)
|
|
{
|
|
call_stack_push(expression.str());
|
|
check_breakpoints();
|
|
msg(" evaluating expression: ",call_stack_.back());
|
|
variant v = expression.execute(variables,this);
|
|
call_stack_set_value(v);
|
|
call_stack_set_evaluated(true);
|
|
msg(" evaluated expression: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
|
|
check_breakpoints();
|
|
call_stack_pop();
|
|
return v;
|
|
}
|
|
|
|
|
|
variant formula_debugger::evaluate_formula_callback(const formula &f, const formula_callable &variables)
|
|
{
|
|
call_stack_push(f.str());
|
|
check_breakpoints();
|
|
msg(" evaluating formula: ",call_stack_.back());
|
|
variant v = f.execute(variables,this);
|
|
call_stack_set_value(v);
|
|
call_stack_set_evaluated(true);
|
|
msg(" evaluated formula: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
|
|
check_breakpoints();
|
|
call_stack_pop();
|
|
return v;
|
|
}
|
|
|
|
|
|
variant formula_debugger::evaluate_formula_callback(const formula &f)
|
|
{
|
|
call_stack_push(f.str());
|
|
check_breakpoints();
|
|
msg(" evaluating formula without variables: ",call_stack_.back());
|
|
variant v = f.execute(this);
|
|
call_stack_set_value(v);
|
|
call_stack_set_evaluated(true);
|
|
msg(" evaluated formula without variables: ",call_stack_.back()," to ",v.to_debug_string(NULL,true).c_str());
|
|
check_breakpoints();
|
|
call_stack_pop();
|
|
return v;
|
|
}
|
|
|
|
|
|
base_breakpoint::base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only)
|
|
: fdb_(fdb), name_(name), one_time_only_(one_time_only)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
base_breakpoint::~base_breakpoint()
|
|
{
|
|
}
|
|
|
|
|
|
bool base_breakpoint::is_one_time_only() const
|
|
{
|
|
return one_time_only_;
|
|
}
|
|
|
|
|
|
const std::string& base_breakpoint::name() const
|
|
{
|
|
return name_;
|
|
}
|
|
|
|
class end_breakpoint : public base_breakpoint {
|
|
public:
|
|
end_breakpoint(formula_debugger &fdb)
|
|
: base_breakpoint(fdb,"End", true)
|
|
{
|
|
}
|
|
|
|
virtual ~end_breakpoint()
|
|
{
|
|
}
|
|
|
|
virtual bool is_break_now() const
|
|
{
|
|
const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
|
|
if ((call_stack.size() == 1) && (call_stack[0].evaluated()) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class step_in_breakpoint : public base_breakpoint {
|
|
public:
|
|
step_in_breakpoint(formula_debugger &fdb)
|
|
: base_breakpoint(fdb,"Step",true)
|
|
{
|
|
}
|
|
|
|
virtual ~step_in_breakpoint()
|
|
{
|
|
}
|
|
|
|
virtual bool is_break_now() const
|
|
{
|
|
const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
|
|
if (call_stack.empty() || call_stack.back().evaluated()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
class step_out_breakpoint : public base_breakpoint {
|
|
public:
|
|
step_out_breakpoint(formula_debugger &fdb)
|
|
: base_breakpoint(fdb,"Step out",true), level_(fdb.get_call_stack().size()-1)
|
|
{
|
|
}
|
|
|
|
virtual ~step_out_breakpoint()
|
|
{
|
|
}
|
|
|
|
virtual bool is_break_now() const
|
|
{
|
|
const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
|
|
if (call_stack.empty() || call_stack.back().evaluated()) {
|
|
return false;
|
|
}
|
|
|
|
if (call_stack.size() == level_) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
private:
|
|
size_t level_;
|
|
};
|
|
|
|
|
|
class next_breakpoint : public base_breakpoint {
|
|
public:
|
|
next_breakpoint(formula_debugger &fdb)
|
|
: base_breakpoint(fdb,"Next",true), level_(fdb.get_call_stack().size())
|
|
{
|
|
}
|
|
|
|
virtual ~next_breakpoint()
|
|
{
|
|
}
|
|
|
|
virtual bool is_break_now() const
|
|
{
|
|
const std::deque<debug_info> &call_stack = fdb_.get_call_stack();
|
|
if (call_stack.empty() || call_stack.back().evaluated()) {
|
|
return false;
|
|
}
|
|
if (call_stack.size() == level_) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
private:
|
|
size_t level_;
|
|
};
|
|
|
|
|
|
void formula_debugger::add_breakpoint_continue_to_end()
|
|
{
|
|
breakpoints_.push_back(breakpoint_ptr(new end_breakpoint(*this)));
|
|
LOG_FDB << "added 'end' breakpoint"<< std::endl;
|
|
}
|
|
|
|
|
|
void formula_debugger::add_breakpoint_step_into()
|
|
{
|
|
breakpoints_.push_back(breakpoint_ptr(new step_in_breakpoint(*this)));
|
|
LOG_FDB << "added 'step into' breakpoint"<< std::endl;
|
|
}
|
|
|
|
|
|
void formula_debugger::add_breakpoint_step_out()
|
|
{
|
|
breakpoints_.push_back(breakpoint_ptr(new step_out_breakpoint(*this)));
|
|
LOG_FDB << "added 'step out' breakpoint"<< std::endl;
|
|
}
|
|
|
|
|
|
void formula_debugger::add_breakpoint_next()
|
|
{
|
|
breakpoints_.push_back(breakpoint_ptr(new next_breakpoint(*this)));
|
|
LOG_FDB << "added 'next' breakpoint"<< std::endl;
|
|
}
|
|
|
|
|
|
} // end of namespace game_logic
|