Formula AI Debugger (uses --new-widgets )

This commit is contained in:
Iurii Chernyi 2009-08-17 15:06:13 +00:00
parent 40b0ee8f1a
commit 498c4f8977
22 changed files with 1186 additions and 67 deletions

View file

@ -1,4 +1,6 @@
Version 1.7.3+svn:
* AI:
* Formula AI debugger (uses -new-widgets)
* Language and i18n:
* Updated translations:
* Miscellaneous and bugfixes:

View file

@ -0,0 +1,228 @@
#textdomain wesnoth-lib
###
### Definition of the window to control formula debugger.
###
[window]
id = "formula_debugger"
description = "Formula debugger dialog."
[resolution]
definition = "default"
automatic_placement = "true"
vertical_placement = "center"
horizontal_placement = "center"
[grid]
[row] #header
grow_factor = 0
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "title"
label = _ "Formula debugger"
[/label]
[/column]
[column]
grow_factor = 0
[spacer]
definition = "default"
[/spacer]
[/column]
[/row]
[row] #menu
grow_factor = 0
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "default"
label= _ "Welcome"
[/label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
id="state"
definition = "default"
label= _ "state"
[/label]
[/column]
[/row]
[row] #stack-title
grow_factor = 2
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "default"
label= _ "Call stack"
[/label]
[/column]
[column]
grow_factor = 0
horizontal_alignment="center"
[label]
definition = "default"
label = _ "Actions"
[/label]
[/column]
[/row]
[row] #stack-main
grow_factor = 2
[column]
grow_factor = 7
border = "all"
border_size = 5
vertical_alignment = "top"
horizontal_alignment = "left"
[scroll_label]
id = "stack"
definition = "default"
[/scroll_label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_alignment = "center"
vertical_alignment = "top"
[grid]
[row]
grow_factor=0
[column]
grow_factor=0
[button]
id = "step"
definition = "default"
label = _ "Step operation"
[/button]
[/column][/row]
[row]
grow_factor=0
[column]
grow_factor=0
[button]
id = "next"
definition = "default"
label = _ "Next operation"
[/button]
[/column][/row]
[row]
grow_factor=0
grow_factor=0
[column]
[button]
id = "stepout"
definition = "default"
label = _ "Step out"
[/button]
[/column][/row]
[row]
grow_factor=0
[column]
grow_factor=0
[button]
id = "continue"
definition = "default"
label = _ "Continue"
[/button]
[/column][/row]
[/grid]
[/column]
[/row]
[row] #trace-title
grow_factor = 0
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "default"
label= _ "Execution trace"
[/label]
[/column]
[column]
grow_factor = 0
horizontal_alignment="center"
[spacer]
definition = "default"
[/spacer]
[/column]
[/row]
[row] #trace-main
grow_factor = 6
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[scroll_label]
id = "execution"
definition = "default"
[/scroll_label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[spacer]
definition = "default"
[/spacer]
[/column]
[/row]
[row] #status
grow_factor = 0
[column]
grow_factor = 7
border = "all"
border_size = 5
horizontal_alignment = "left"
[spacer]
definition = "default"
[/spacer]
[/column]
[column]
grow_factor = 0
[button]
id = "cancel"
definition = "default"
label = _ "Quit"
[/button]
[/column]
[/row]
[/grid]
[/resolution]
[/window]

View file

@ -188,6 +188,8 @@
<Unit filename="..\..\src\formula_callable.hpp" />
<Unit filename="..\..\src\formula_debugger.cpp" />
<Unit filename="..\..\src\formula_debugger.hpp" />
<Unit filename="..\..\src\formula_debugger_fwd.cpp" />
<Unit filename="..\..\src\formula_debugger_fwd.hpp" />
<Unit filename="..\..\src\formula_function.cpp" />
<Unit filename="..\..\src\formula_function.hpp" />
<Unit filename="..\..\src\formula_string_utils.cpp" />
@ -285,6 +287,8 @@
<Unit filename="..\..\src\gui\dialogs\editor_settings.hpp" />
<Unit filename="..\..\src\gui\dialogs\field-fwd.hpp" />
<Unit filename="..\..\src\gui\dialogs\field.hpp" />
<Unit filename="..\..\src\gui\dialogs\formula_debugger.cpp" />
<Unit filename="..\..\src\gui\dialogs\formula_debugger.hpp" />
<Unit filename="..\..\src\gui\dialogs\game_delete.cpp" />
<Unit filename="..\..\src\gui\dialogs\game_delete.hpp" />
<Unit filename="..\..\src\gui\dialogs\game_load.cpp" />

View file

@ -217,6 +217,8 @@
<Unit filename="..\..\src\formula_callable.hpp" />
<Unit filename="..\..\src\formula_debugger.cpp" />
<Unit filename="..\..\src\formula_debugger.hpp" />
<Unit filename="..\..\src\formula_debugger_fwd.cpp" />
<Unit filename="..\..\src\formula_debugger_fwd.hpp" />
<Unit filename="..\..\src\formula_function.cpp" />
<Unit filename="..\..\src\formula_function.hpp" />
<Unit filename="..\..\src\formula_string_utils.cpp" />
@ -314,6 +316,8 @@
<Unit filename="..\..\src\gui\dialogs\editor_settings.hpp" />
<Unit filename="..\..\src\gui\dialogs\field-fwd.hpp" />
<Unit filename="..\..\src\gui\dialogs\field.hpp" />
<Unit filename="..\..\src\gui\dialogs\formula_debugger.cpp" />
<Unit filename="..\..\src\gui\dialogs\formula_debugger.hpp" />
<Unit filename="..\..\src\gui\dialogs\game_delete.cpp" />
<Unit filename="..\..\src\gui\dialogs\game_delete.hpp" />
<Unit filename="..\..\src\gui\dialogs\game_load.cpp" />

View file

@ -357,6 +357,10 @@
RelativePath="..\..\src\formula_debugger.cpp"
>
</File>
<File
RelativePath="..\..\src\formula_debugger_fwd.cpp"
>
</File>
<File
RelativePath="..\..\src\formula_function.cpp"
>
@ -1871,6 +1875,34 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\gui\dialogs\formula_debugger.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\Gui\Dialogs\"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\Gui\Dialogs\"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug (fast)|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\Gui\Dialogs\"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\gui\dialogs\game_delete.cpp"
>
@ -4828,6 +4860,10 @@
RelativePath="..\..\src\formula_debugger.hpp"
>
</File>
<File
RelativePath="..\..\src\formula_debugger_fwd.hpp"
>
</File>
<File
RelativePath="..\..\src\formula_function.hpp"
>
@ -5358,6 +5394,10 @@
RelativePath="..\..\src\gui\dialogs\field.hpp"
>
</File>
<File
RelativePath="..\..\src\gui\dialogs\formula_debugger.hpp"
>
</File>
<File
RelativePath="..\..\src\gui\dialogs\game_load.hpp"
>

View file

@ -265,6 +265,7 @@ SET(wesnoth-main_SRC
floating_textbox.cpp
formula.cpp
formula_debugger.cpp
formula_debugger_fwd.cpp
formula_function.cpp
formula_tokenizer.cpp
formula_string_utils.cpp
@ -303,6 +304,7 @@ SET(wesnoth-main_SRC
gui/dialogs/addon_list.cpp
gui/dialogs/campaign_selection.cpp
gui/dialogs/dialog.cpp
gui/dialogs/formula_debugger.cpp
gui/dialogs/game_load.cpp
gui/dialogs/game_delete.cpp
gui/dialogs/game_save.cpp

View file

@ -86,6 +86,7 @@ wesnoth_source = \
floating_textbox.cpp \
formula.cpp \
formula_debugger.cpp \
formula_debugger_fwd.cpp \
formula_function.cpp \
formula_tokenizer.cpp \
formula_string_utils.cpp \
@ -124,6 +125,7 @@ wesnoth_source = \
gui/dialogs/addon_list.cpp \
gui/dialogs/campaign_selection.cpp \
gui/dialogs/dialog.cpp \
gui/dialogs/formula_debugger.cpp \
gui/dialogs/game_load.cpp \
gui/dialogs/game_delete.cpp \
gui/dialogs/game_save.cpp \

View file

@ -191,6 +191,7 @@ wesnoth_sources = Split("""
floating_textbox.cpp
formula.cpp
formula_debugger.cpp
formula_debugger_fwd.cpp
formula_function.cpp
formula_tokenizer.cpp
formula_string_utils.cpp
@ -283,6 +284,7 @@ wesnoth_sources = Split("""
gui/dialogs/addon_list.cpp
gui/dialogs/campaign_selection.cpp
gui/dialogs/dialog.cpp
gui/dialogs/formula_debugger.cpp
gui/dialogs/game_load.cpp
gui/dialogs/game_delete.cpp
gui/dialogs/game_save.cpp

View file

@ -30,6 +30,7 @@
#include "../manager.hpp"
#include "../../foreach.hpp"
#include "../../formula_debugger.hpp"
#include "../../log.hpp"
#include "../../menu_events.hpp"

View file

@ -387,8 +387,8 @@ public:
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const map_location loc = convert_variant<location_callable>(args()[0]->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"nearest_loc:location")))->loc();
variant items = args()[1]->evaluate(variables,formula_debugger::add_debug_info(fdb,1,"nearest_loc:locations"));
const map_location loc = convert_variant<location_callable>(args()[0]->evaluate(variables,add_debug_info(fdb,0,"nearest_loc:location")))->loc();
variant items = args()[1]->evaluate(variables,add_debug_info(fdb,1,"nearest_loc:locations"));
int best = 1000000;
int best_i = -1;
@ -615,7 +615,7 @@ public:
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const map_location loc = convert_variant<location_callable>(args()[0]->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"nearest_keep:location")))->loc();
const map_location loc = convert_variant<location_callable>(args()[0]->evaluate(variables,add_debug_info(fdb,0,"nearest_keep:location")))->loc();
int best = 1000000;
int best_i = -1;
@ -1235,7 +1235,7 @@ public:
{}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
variant res = args()[0]->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"unit_moves:unit_location"));
variant res = args()[0]->evaluate(variables,add_debug_info(fdb,0,"unit_moves:unit_location"));
std::vector<variant> vars;
if(res.is_null()) {
return variant(&vars);

View file

@ -16,7 +16,7 @@
#include <iostream>
#include <set>
//#include "foreach.hpp"
#include "foreach.hpp"
#include "formula_callable.hpp"
#include "formula_function.hpp"
#include "map_utils.hpp"
@ -29,6 +29,7 @@ void formula_callable::set_value(const std::string& key, const variant& /*value*
std::cerr << "ERROR: cannot set key '" << key << "' on object\n";
}
map_formula_callable::map_formula_callable(
const formula_callable* fallback) :
formula_callable(false),
@ -72,6 +73,10 @@ public:
: symbols_(symbols)
{}
virtual std::string str() const
{
return "{function_list_expression()}";
}
private:
variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
std::vector<variant> res;
@ -105,6 +110,25 @@ private:
}
std::vector<expression_ptr> items_;
std::string str() const
{
std::stringstream s;
s << '[';
bool first_item = true;
foreach(expression_ptr a , items_) {
if (!first_item) {
s << ',';
} else {
first_item = false;
}
s << a->str();
}
s << ']';
return s.str();
}
};
class map_expression : public formula_expression {
@ -113,6 +137,20 @@ public:
: items_(items)
{}
virtual std::string str() const
{
std::stringstream s;
s << "{map_expression:(";
for(std::vector<expression_ptr>::const_iterator i = items_.begin(); ( i != items_.end() ) && ( i+1 != items_.end() ) ; i+=2) {
s << "[";
s << (*i)->str();
s << "] -> [";
s << (*(i+1))->str();
s << "]";
}
s << ")";
return s.str();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
std::map<variant,variant> res;
@ -131,7 +169,7 @@ private:
class unary_operator_expression : public formula_expression {
public:
unary_operator_expression(const std::string& op, expression_ptr arg) :
op_(),
op_(),op_str_(op),
operand_(arg)
{
if(op == "not") {
@ -142,6 +180,13 @@ public:
throw formula_error("Illegal unary operator: '" + op + "'" , "", "", 0);
}
}
virtual std::string str() const {
std::stringstream s;
s << op_str_ << '('<< operand_->str() << ')';
return s.str();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const variant res = operand_->evaluate(variables,fdb);
@ -155,6 +200,7 @@ private:
}
enum OP { NOT, SUB };
OP op_;
std::string op_str_;
expression_ptr operand_;
};
@ -192,6 +238,7 @@ public:
return variant();
}
}
};
class dot_callable : public formula_callable {
@ -221,9 +268,15 @@ public:
dot_expression(expression_ptr left, expression_ptr right)
: left_(left), right_(right)
{}
std::string str() const
{
std::stringstream s;
s << left_->str() << "." << right_->str();
return s.str();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const variant left = left_->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"left."));
const variant left = left_->evaluate(variables,add_debug_info(fdb,0,"left."));
if(!left.is_callable()) {
if(left.is_list()) {
list_callable list_call(left);
@ -235,7 +288,7 @@ private:
}
dot_callable callable(variables, *left.as_callable());
return right_->evaluate(callable,formula_debugger::add_debug_info(fdb,1,".right"));
return right_->evaluate(callable,add_debug_info(fdb,1,".right"));
}
expression_ptr left_, right_;
@ -246,6 +299,13 @@ public:
square_bracket_expression(expression_ptr left, expression_ptr key)
: left_(left), key_(key)
{}
std::string str() const
{
std::stringstream s;
s << left_->str() << '[' << key_->str() << ']';
return s.str();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const variant left = left_->evaluate(variables,fdb);
@ -264,7 +324,7 @@ class operator_expression : public formula_expression {
public:
operator_expression(const std::string& op, expression_ptr left,
expression_ptr right)
: op_(OP(op[0])), left_(left), right_(right)
: op_(OP(op[0])), op_str_(op), left_(left), right_(right)
{
if(op == ">=") {
op_ = GTE;
@ -287,10 +347,16 @@ public:
}
}
std::string str() const
{
std::stringstream s;
s << left_->str() << op_str_ << right_->str();
return s.str();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
const variant left = left_->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"left_OP"));
const variant right = right_->evaluate(variables,formula_debugger::add_debug_info(fdb,1,"OP_right"));
const variant left = left_->evaluate(variables,add_debug_info(fdb,0,"left_OP"));
const variant right = right_->evaluate(variables,add_debug_info(fdb,1,"OP_right"));
switch(op_) {
case AND:
return left.as_bool() == false ? left : right;
@ -346,6 +412,7 @@ private:
ADD='+', SUB='-', MUL='*', DIV='/', ADDL, SUBL, MULL, DIVL, DICE='d', POW='^', MOD='%' };
OP op_;
std::string op_str_;
expression_ptr left_, right_;
};
@ -391,6 +458,18 @@ public:
: body_(body), clauses_(clauses)
{}
std::string str() const
{
std::stringstream s;
s << "{where:(";
s << body_->str();
foreach (const expr_table::value_type &a, *clauses_) {
s << ", [" << a.first << "] -> ["<< a.second->str()<<"]";
}
s << ")}";
return s.str();
}
private:
expression_ptr body_;
expr_table_ptr clauses_;
@ -406,6 +485,10 @@ class identifier_expression : public formula_expression {
public:
explicit identifier_expression(const std::string& id) : id_(id)
{}
std::string str() const
{
return id_;
}
private:
variant execute(const formula_callable& variables, formula_debugger * /*fdb*/) const {
return variables.query_value(id_);
@ -416,6 +499,9 @@ private:
class null_expression : public formula_expression {
public:
explicit null_expression() {};
std::string str() const {
return "";
}
private:
variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
return variant();
@ -427,6 +513,12 @@ class integer_expression : public formula_expression {
public:
explicit integer_expression(int i) : i_(i)
{}
std::string str() const
{
std::stringstream s;
s << i_;
return s.str();
}
private:
variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
return variant(i_);
@ -439,6 +531,13 @@ class decimal_expression : public formula_expression {
public:
explicit decimal_expression(int i, int f) : i_(i), f_(f)
{}
std::string str() const
{
std::stringstream s;
s << i_ << '.' << f_;
return s.str();
}
private:
variant execute(const formula_callable& /*variables*/, formula_debugger * /*fdb*/) const {
return variant(i_ * 1000 + f_, variant::DECIMAL_VARIANT );
@ -474,6 +573,11 @@ public:
str_ = variant(str);
}
std::string str() const
{
return str_.as_string();
}
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
if(subs_.empty()) {

View file

@ -17,7 +17,7 @@
#include <map>
#include <string>
#include "formula_debugger.hpp"
#include "formula_debugger_fwd.hpp"
#include "formula_fwd.hpp"
#include "formula_tokenizer.hpp"
#include "variant.hpp"
@ -45,7 +45,7 @@ public:
variant evaluate(const formula_callable& variables, formula_debugger *fdb = NULL) const
{
if (fdb!=NULL) {
return fdb->evaluate_formula_callback(*this,variables);
return evaluate_formula_callback(*fdb,*this,variables);
} else {
return execute(variables,fdb);
}
@ -54,7 +54,7 @@ public:
variant evaluate(formula_debugger *fdb = NULL) const
{
if (fdb!=NULL) {
return fdb->evaluate_formula_callback(*this);
return evaluate_formula_callback(*fdb,*this);
} else {
return execute(fdb);
}

View file

@ -21,7 +21,11 @@
#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>
@ -33,14 +37,9 @@ static lg::log_domain log_formula_debugger("ai/debug/formula");
namespace game_logic {
debug_info::debug_info()
: arg_number_(-1),f_name_(""),valid_(false)
{
}
debug_info::debug_info(int arg_number, const char *f_name, bool valid)
: arg_number_(arg_number), f_name_(f_name), valid_(valid)
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)
{
}
@ -50,25 +49,58 @@ debug_info::~debug_info()
}
const char* debug_info::name()
int debug_info::level() const
{
if (valid_ && (f_name_!=NULL) ) {
return f_name_;
} else {
return "";
}
return level_;
}
const std::string& debug_info::name() const
{
return name_;
}
void debug_info::invalidate()
int debug_info::counter() const
{
valid_ = false;
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()
: counter_(0), info_()
: 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();
}
@ -77,52 +109,284 @@ formula_debugger::~formula_debugger()
}
static void msg(int counter, const char *act, const char *name, const char *formula_str, const char *to="", const char *result = "")
static void msg(const char *act, debug_info &i, const char *to="", const char *result = "")
{
DBG_FDB << "#" << counter << act << std::endl <<" \""<< name << "\"='" << formula_str << "' " << to << result << std::endl;
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)
{
info_ = debug_info(arg_number,f_name, true);
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)
{
int counter = counter_++;
debug_info i = info_;
info_.invalidate();
msg(counter," evaluating expression: ",i.name(),"");
variant v = expression.execute(variables,this); //work-in-progress
msg(counter," evaluated expression: ",i.name(),""," to ",v.to_debug_string(NULL,true).c_str());
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)
{
int counter = counter_++;
debug_info i = info_;
info_.invalidate();
msg(counter," evaluating formula: ",i.name(),f.str().c_str());
variant v = f.execute(variables,this); //work-in-progress
msg(counter," evaluated formula: ",i.name(),f.str().c_str()," to ",v.to_debug_string(NULL,true).c_str());
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)
{
int counter = counter_++;
debug_info i = info_;
info_.invalidate();
msg(counter," evaluating formula without variables: ",i.name(),f.str().c_str());
variant v = f.execute(this); //work-in-progress
msg(counter," evaluating formula without variables: ",i.name(),f.str().c_str(),v.to_debug_string(NULL,true).c_str());
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

View file

@ -25,45 +25,116 @@
#include "global.hpp"
#include "variant.hpp"
#include "formula_debugger_fwd.hpp"
#include <deque>
namespace game_logic {
class formula_expression;
class formula_callable;
class formula;
class formula_debugger;
class debug_info {
public:
debug_info();
debug_info(int arg_number, const char *f_name, bool valid);
debug_info(int arg_number, int counter, int level, const std::string &name, const std::string &str, const variant &value, bool evaluated);
virtual ~debug_info();
const char* name();
void invalidate();
int counter() const;
int level() const;
const std::string& name() const;
const std::string& str() const;
const variant& value() const;
const std::string& value_str() const;
bool evaluated() const;
void set_evaluated(bool evaluated);
void set_value(const variant &value);
private:
int arg_number_;
const char *f_name_;
bool valid_;
int counter_;
int level_;
std::string name_;
std::string str_;
variant value_;
bool evaluated_;
};
class base_breakpoint {
public:
base_breakpoint(formula_debugger &fdb, const std::string &name, bool one_time_only);
virtual ~base_breakpoint();
virtual bool is_break_now() const = 0;
bool is_one_time_only() const;
const std::string &name() const;
protected:
formula_debugger &fdb_;
std::string name_;
bool one_time_only_;
};
class formula_debugger {
public:
formula_debugger();
virtual ~formula_debugger();
virtual void add_debug_info(int arg_number, const char *f_name);
void add_debug_info(int arg_number, const char *f_name);
virtual variant evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables);
void call_stack_push(const std::string &str);
void call_stack_pop();
void call_stack_set_evaluated(bool evaluated);
virtual variant evaluate_formula_callback(const formula &f, const formula_callable &variables);
void call_stack_set_value(const variant &v);
virtual variant evaluate_formula_callback(const formula &f);
void check_breakpoints();
const std::deque<debug_info>& get_call_stack() const;
const breakpoint_ptr get_current_breakpoint() const;
const std::deque<debug_info>& get_execution_trace() const;
variant evaluate_arg_callback(const formula_expression &expression, const formula_callable &variables);
variant evaluate_formula_callback(const formula &f, const formula_callable &variables);
variant evaluate_formula_callback(const formula &f);
void show_gui();
void add_breakpoint_continue_to_end();
void add_breakpoint_step_into();
void add_breakpoint_step_out();
void add_breakpoint_next();
//static functions
static formula_debugger* add_debug_info(formula_debugger *fdb, int arg_number, const char *f_name)
{
if (fdb==NULL) {
@ -74,8 +145,15 @@ public:
}
private:
std::deque<debug_info> call_stack_;
int counter_;
debug_info info_;
breakpoint_ptr current_breakpoint_;
std::deque< breakpoint_ptr > breakpoints_;
std::deque<debug_info> execution_trace_;
int arg_number_extra_debug_info;
const char *f_name_extra_debug_info;
};

View file

@ -0,0 +1,54 @@
/* $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 formula_debugger_fwd.cpp
* Formula debugger - forward declaration and add_debug_info static function
* */
#include "formula_debugger_fwd.hpp"
#include "formula_debugger.hpp"
namespace game_logic {
formula_debugger* add_debug_info(formula_debugger *fdb, int arg_number, const char *f_name)
{
if (fdb==NULL) {
return NULL;
}
fdb->add_debug_info(arg_number,f_name);
return fdb;
}
variant evaluate_arg_callback(formula_debugger &fdb, const formula_expression &expression, const formula_callable &variables)
{
return fdb.evaluate_arg_callback(expression,variables);
}
variant evaluate_formula_callback(formula_debugger &fdb, const formula &f, const formula_callable &variables)
{
return fdb.evaluate_formula_callback(f,variables);
}
variant evaluate_formula_callback(formula_debugger &fdb, const formula &f)
{
return fdb.evaluate_formula_callback(f);
}
} // end of namespace game_logic

View file

@ -0,0 +1,57 @@
/* $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 formula_debugger_fwd.hpp
* Formula AI debugger, forward
*
*/
#ifndef FORMULA_DEBUGGER_FWD_HPP_INCLUDED
#define FORMULA_DEBUGGER_FWD_HPP_INCLUDED
#include "global.hpp"
#include "variant.hpp"
#include <boost/shared_ptr.hpp>
#include <deque>
class variant;
namespace game_logic {
class formula_debugger;
class debug_info;
class formula_expression;
class formula;
class formula_callable;
class base_breakpoint;
typedef boost::shared_ptr<base_breakpoint> breakpoint_ptr;
formula_debugger* add_debug_info(formula_debugger *fdb, int arg_number, const char *f_name);
variant evaluate_arg_callback(formula_debugger &fdb, const formula_expression &expression, const formula_callable &variables);
variant evaluate_formula_callback(formula_debugger &fdb, const formula &f, const formula_callable &variables);
variant evaluate_formula_callback(formula_debugger &fdb, const formula &f);
} // end of namespace game_logic
#endif

View file

@ -29,6 +29,25 @@ static lg::log_domain log_scripting_formula("scripting/formula");
namespace game_logic {
std::string function_expression::str() const
{
std::stringstream s;
s << get_name();
s << '(';
bool first_arg = true;
foreach(expression_ptr a , args()) {
if (!first_arg) {
s << ',';
} else {
first_arg = false;
}
s << a->str();
}
s << ')';
return s.str();
}
namespace {
class dir_function : public function_expression {
@ -813,8 +832,8 @@ public:
private:
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
return variant(new location_callable(map_location(
args()[0]->evaluate(variables,formula_debugger::add_debug_info(fdb,0,"loc:x")).as_int()-1,
args()[1]->evaluate(variables,formula_debugger::add_debug_info(fdb,1,"loc:y")).as_int()-1)));
args()[0]->evaluate(variables,add_debug_info(fdb,0,"loc:x")).as_int()-1,
args()[1]->evaluate(variables,add_debug_info(fdb,1,"loc:y")).as_int()-1)));
}
};

View file

@ -1,3 +1,4 @@
/* $Id$ */
/*
Copyright (C) 2008 - 2009 by David White <dave@whitevine.net>
@ -21,7 +22,7 @@
#include "formula.hpp"
#include "formula_callable.hpp"
#include "formula_debugger.hpp"
#include "formula_debugger_fwd.hpp"
#include "variant.hpp"
namespace game_logic {
@ -33,7 +34,7 @@ public:
variant evaluate(const formula_callable& variables, formula_debugger *fdb = NULL) const {
call_stack_manager manager(name_);
if (fdb!=NULL) {
return fdb->evaluate_arg_callback(*this,variables);
return evaluate_arg_callback(*fdb,*this,variables);
} else {
return execute(variables,fdb);
}
@ -41,6 +42,7 @@ public:
void set_name(const char* name) { name_ = name; }
const char* get_name() const { return name_; }
virtual std::string str() const = 0;
private:
virtual variant execute(const formula_callable& variables, formula_debugger *fdb = NULL) const = 0;
const char* name_;
@ -67,7 +69,7 @@ public:
throw formula_error("Too many arguments", "", "", 0);
}
}
virtual std::string str() const;
protected:
const args_list& args() const { return args_; }
private:

View file

@ -0,0 +1,196 @@
/* $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.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/dialogs/formula_debugger.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/window.hpp"
#include "../../foreach.hpp"
#include "../../formula_debugger.hpp"
#include <boost/bind.hpp>
namespace gui2 {
//ugly hack, should be removed as soon as boost::bind works with tbutton callbacks
static tformula_debugger *td;
namespace {
void formula_debugger_callback_continue_function(gui2::twidget *caller)
{
if (td==NULL) {
return;
}
td->callback_continue_button(caller);
}
void formula_debugger_callback_next_function(gui2::twidget *caller)
{
if (td==NULL) {
return;
}
td->callback_next_button(caller);
}
void formula_debugger_callback_step_function(gui2::twidget *caller)
{
if (td==NULL) {
return;
}
td->callback_step_button(caller);
}
void formula_debugger_callback_stepout_function(gui2::twidget *caller)
{
if (td==NULL) {
return;
}
td->callback_stepout_button(caller);
}
} //of namespace {
twindow* tformula_debugger::build_window(CVideo& video)
{
return build(video, get_id(FORMULA_DEBUGGER));
}
void tformula_debugger::pre_show(CVideo& /*video*/, twindow& window)
{
//hack
td = this;
// stack label
tcontrol* stack_label =
dynamic_cast<tcontrol*>(window.find_widget("stack", false));
VALIDATE(stack_label, missing_widget("stack"));
std::stringstream stack_text;
std::string indent = " ";
int c = 0;
foreach (const game_logic::debug_info &i, fdb_.get_call_stack()) {
for (int d=0; d<c; d++) {
stack_text << indent;
}
stack_text << "#<span color=\"green\">" << i.counter() <<"</span>: \"<span color=\"green\">"<< i.name() << "</span>\": '" << i.str() << "' " << std::endl;
c++;
}
stack_label->set_markup_mode(tcontrol::PANGO_MARKUP);
stack_label->set_label(stack_text.str());
window.keyboard_capture(stack_label);
// execution trace label
tcontrol* execution_label =
dynamic_cast<tcontrol*>(window.find_widget("execution", false));
VALIDATE(execution_label, missing_widget("execution"));
std::stringstream execution_text;
foreach (const game_logic::debug_info &i, fdb_.get_execution_trace()) {
for (int d=0; d<i.level(); d++) {
execution_text << indent;
}
if (!i.evaluated() ) {
execution_text << "#<span color=\"green\">" << i.counter() <<"</span>: \"<span color=\"green\">"<< i.name() << "</span>\": '" << i.str() << "' " << std::endl;
} else {
execution_text << "#<span color=\"yellow\">" << i.counter() <<"</span>: \"<span color=\"yellow\">"<< i.name() << "</span>\": '" << i.str() << "' = " << "<span color=\"red\">"<< i.value().to_debug_string(NULL,true) <<"</span>" << std::endl;
}
}
execution_label->set_markup_mode(tcontrol::PANGO_MARKUP);
execution_label->set_label(execution_text.str());
// state
std::string state_str;
bool is_end = false;
if (!fdb_.get_current_breakpoint()) {
state_str = "";
} else {
state_str = fdb_.get_current_breakpoint()->name();
if (state_str=="End") {
is_end = true;
}
}
tcontrol* state_label =
dynamic_cast<tcontrol*>(window.find_widget("state", false));
VALIDATE(state_label, missing_widget("state"));
state_label->set_label(state_str);
// callbacks
tbutton* step_button =
dynamic_cast<tbutton*>(window.find_widget("step", false));
VALIDATE(step_button, missing_widget("step"));
step_button->set_callback_mouse_left_click(formula_debugger_callback_step_function);
tbutton* stepout_button =
dynamic_cast<tbutton*>(window.find_widget("stepout", false));
VALIDATE(stepout_button, missing_widget("stepout"));
stepout_button->set_callback_mouse_left_click(formula_debugger_callback_stepout_function);
tbutton* next_button =
dynamic_cast<tbutton*>(window.find_widget("next", false));
VALIDATE(next_button, missing_widget("next"));
next_button->set_callback_mouse_left_click(formula_debugger_callback_next_function);
tbutton* continue_button =
dynamic_cast<tbutton*>(window.find_widget("continue", false));
VALIDATE(continue_button, missing_widget("continue"));
continue_button->set_callback_mouse_left_click(formula_debugger_callback_continue_function);
if (is_end) {
step_button->set_active(false);
stepout_button->set_active(false);
next_button->set_active(false);
continue_button->set_active(false);
}
}
void tformula_debugger::callback_continue_button(gui2::twidget* caller)
{
fdb_.add_breakpoint_continue_to_end();
caller->get_window()->set_retval(twindow::OK);
}
void tformula_debugger::callback_next_button(gui2::twidget* caller)
{
fdb_.add_breakpoint_next();
caller->get_window()->set_retval(twindow::OK);
}
void tformula_debugger::callback_step_button(gui2::twidget* caller)
{
fdb_.add_breakpoint_step_into();
caller->get_window()->set_retval(twindow::OK);
}
void tformula_debugger::callback_stepout_button(gui2::twidget* caller)
{
fdb_.add_breakpoint_step_out();
caller->get_window()->set_retval(twindow::OK);
}
} //end of namespace gui2

View file

@ -0,0 +1,58 @@
/* $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.
*/
#ifndef GUI_DIALOGS_FORMULA_DEBUGGER_HPP_INCLUDED
#define GUI_DIALOGS_FORMULA_DEBUGGER_HPP_INCLUDED
#include "gui/dialogs/dialog.hpp"
namespace game_logic {
class formula_debugger;
}
namespace gui2 {
class tformula_debugger : public tdialog
{
public:
tformula_debugger(game_logic::formula_debugger &fdb) :
fdb_(fdb)
{}
/** Inherited from tdialog. */
twindow* build_window(CVideo& video);
/** Inherited from tdialog. */
void pre_show(CVideo& video, twindow& window);
void callback_continue_button(gui2::twidget *caller);
void callback_next_button(gui2::twidget *caller);
void callback_step_button(gui2::twidget *caller);
void callback_stepout_button(gui2::twidget *caller);
private:
game_logic::formula_debugger &fdb_;
};
}
#endif /* ! GUI_DIALOGS_FORMULA_DEBUGGER_HPP_INCLUDED */

View file

@ -102,6 +102,7 @@ static void fill_window_types()
window_type_list[LOBBY_MAIN] = "lobby_main";
window_type_list[LOBBY_PLAYER_INFO] = "lobby_player_info";
window_type_list[UNIT_CREATE] = "unit_create";
window_type_list[FORMULA_DEBUGGER] = "formula_debugger";
}
const std::string& get_id(const twindow_type window_type)

View file

@ -75,6 +75,7 @@ enum twindow_type {
LOBBY_MAIN, /**< Main MP lobby screen */
LOBBY_PLAYER_INFO, /**< MP lobby player info dialog */
UNIT_CREATE, /**< Debug-mode unit creation dialog */
FORMULA_DEBUGGER, /**< Formula debugger dialog */
COUNT /**<
* The last one to hold the number of items and as
* sentinel.