Merge branch 'lua_formula_bridge'
Allows calling WFL code from Lua
This commit is contained in:
commit
cc7c124744
15 changed files with 580 additions and 203 deletions
|
@ -717,6 +717,7 @@
|
|||
91F462841C71139C0050A9C9 /* preferences_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F462821C71139B0050A9C9 /* preferences_dialog.cpp */; };
|
||||
91F462881C7115C50050A9C9 /* combobox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F462861C7115C50050A9C9 /* combobox.cpp */; };
|
||||
91F462941C7117400050A9C9 /* drop_down_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F462921C7117400050A9C9 /* drop_down_list.cpp */; };
|
||||
91FAC70A1C7FBC3400DAB2C3 /* lua_formula_bridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */; };
|
||||
B504B94C1284C06B00261FE9 /* tips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B504B94A1284C06B00261FE9 /* tips.cpp */; };
|
||||
B508D13F10013BF900B12852 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B508D13E10013BF900B12852 /* Growl.framework */; };
|
||||
B508D14B10013E4700B12852 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = B508D14A10013E4700B12852 /* Growl Registration Ticket.growlRegDict */; };
|
||||
|
@ -1713,6 +1714,8 @@
|
|||
91F462921C7117400050A9C9 /* drop_down_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drop_down_list.cpp; sourceTree = "<group>"; };
|
||||
91F462931C7117400050A9C9 /* drop_down_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = drop_down_list.hpp; sourceTree = "<group>"; };
|
||||
91FAC70B1C80168600DAB2C3 /* group.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = group.hpp; sourceTree = "<group>"; };
|
||||
91FAC7081C7F931900DAB2C3 /* lua_formula_bridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lua_formula_bridge.hpp; sourceTree = "<group>"; };
|
||||
91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_formula_bridge.cpp; sourceTree = "<group>"; };
|
||||
B504B94A1284C06B00261FE9 /* tips.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tips.cpp; sourceTree = "<group>"; };
|
||||
B504B94B1284C06B00261FE9 /* tips.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tips.hpp; sourceTree = "<group>"; };
|
||||
B508D13E10013BF900B12852 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = lib/Growl.framework; sourceTree = "<group>"; };
|
||||
|
@ -4100,6 +4103,8 @@
|
|||
91B621E61B76BB0B00B00E0F /* lua_cpp_function.hpp */,
|
||||
ECA4A6781A1EC319006BCCF2 /* lua_fileops.cpp */,
|
||||
91B621E71B76BB0E00B00E0F /* lua_fileops.hpp */,
|
||||
91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */,
|
||||
91FAC7081C7F931900DAB2C3 /* lua_formula_bridge.hpp */,
|
||||
ECA1E0F11A1271AC00426E00 /* lua_gui2.cpp */,
|
||||
91B621E81B76BB1100B00E0F /* lua_gui2.hpp */,
|
||||
EC218E9F1A106648007C910C /* lua_kernel_base.cpp */,
|
||||
|
@ -5182,6 +5187,7 @@
|
|||
91DCA6891C9066CC0030F8D0 /* unit_preview_pane.cpp in Sources */,
|
||||
91DCA68D1C9066EC0030F8D0 /* unit_recruit.cpp in Sources */,
|
||||
9122417C1CAAB7B7008B347F /* loadscreen.cpp in Sources */,
|
||||
91FAC70A1C7FBC3400DAB2C3 /* lua_formula_bridge.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -561,7 +561,8 @@ variant formula_ai::execute_variant(const variant& var, ai_context &ai_, bool co
|
|||
|
||||
void formula_ai::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
|
||||
{
|
||||
function_table_.add_formula_function(name,formula,precondition,args);
|
||||
formula_function_ptr fcn(new user_formula_function(name,formula,precondition,args));
|
||||
function_table_.add_function(name, fcn);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -376,7 +376,7 @@ private:
|
|||
|
||||
class nearest_loc_function : public function_expression {
|
||||
public:
|
||||
nearest_loc_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
nearest_loc_function(const args_list& args)
|
||||
: function_expression("nearest_loc", args, 2, 2)
|
||||
{
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ private:
|
|||
|
||||
class adjacent_locs_function : public function_expression {
|
||||
public:
|
||||
adjacent_locs_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
adjacent_locs_function(const args_list& args)
|
||||
: function_expression("adjacent_locs", args, 1, 1)
|
||||
{
|
||||
}
|
||||
|
@ -433,7 +433,7 @@ private:
|
|||
|
||||
class locations_in_radius_function : public function_expression {
|
||||
public:
|
||||
locations_in_radius_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
locations_in_radius_function(const args_list& args)
|
||||
: function_expression("locations_in_radius", args, 2, 2)
|
||||
{
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ private:
|
|||
|
||||
class castle_locs_function : public function_expression {
|
||||
public:
|
||||
castle_locs_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
castle_locs_function(const args_list& args)
|
||||
: function_expression("castle_locs", args, 1, 1)
|
||||
{
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ private:
|
|||
*/
|
||||
class timeofday_modifier_function : public function_expression {
|
||||
public:
|
||||
timeofday_modifier_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
timeofday_modifier_function(const args_list& args)
|
||||
: function_expression("timeofday_modifier", args, 1, 2)
|
||||
{
|
||||
}
|
||||
|
@ -725,10 +725,9 @@ private:
|
|||
const formula_ai& ai_;
|
||||
};
|
||||
|
||||
|
||||
class calculate_outcome_function : public function_expression {
|
||||
public:
|
||||
calculate_outcome_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
calculate_outcome_function(const args_list& args)
|
||||
: function_expression( "calculate_outcome", args, 3, 4)
|
||||
{
|
||||
}
|
||||
|
@ -812,7 +811,7 @@ private:
|
|||
|
||||
class outcomes_function : public function_expression {
|
||||
public:
|
||||
outcomes_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
outcomes_function(const args_list& args)
|
||||
: function_expression("outcomes", args, 1, 1)
|
||||
{
|
||||
}
|
||||
|
@ -1175,7 +1174,7 @@ private:
|
|||
|
||||
class attack_function : public function_expression {
|
||||
public:
|
||||
explicit attack_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
explicit attack_function(const args_list& args)
|
||||
: function_expression("attack", args, 3, 4)
|
||||
{}
|
||||
private:
|
||||
|
@ -1303,7 +1302,7 @@ private:
|
|||
|
||||
class unit_at_function : public function_expression {
|
||||
public:
|
||||
unit_at_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
unit_at_function(const args_list& args)
|
||||
: function_expression("unit_at", args, 1, 1)
|
||||
{}
|
||||
private:
|
||||
|
@ -1354,7 +1353,7 @@ private:
|
|||
|
||||
class units_can_reach_function : public function_expression {
|
||||
public:
|
||||
units_can_reach_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
units_can_reach_function(const args_list& args)
|
||||
: function_expression("units_can_reach", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1378,7 +1377,7 @@ private:
|
|||
|
||||
class defense_on_function : public function_expression {
|
||||
public:
|
||||
defense_on_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
defense_on_function(const args_list& args)
|
||||
: function_expression("defense_on", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1428,7 +1427,7 @@ private:
|
|||
|
||||
class chance_to_hit_function : public function_expression {
|
||||
public:
|
||||
chance_to_hit_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
chance_to_hit_function(const args_list& args)
|
||||
: function_expression("chance_to_hit", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1472,7 +1471,7 @@ private:
|
|||
|
||||
class movement_cost_function : public function_expression {
|
||||
public:
|
||||
movement_cost_function(const args_list& args, const formula_ai& /*ai*/)
|
||||
movement_cost_function(const args_list& args)
|
||||
: function_expression("movement_cost", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1533,9 +1532,7 @@ private:
|
|||
|
||||
class max_possible_damage_function : public function_expression {
|
||||
public:
|
||||
max_possible_damage_function(
|
||||
const args_list& args
|
||||
, const formula_ai& /*ai*/)
|
||||
max_possible_damage_function(const args_list& args)
|
||||
: function_expression("max_possible_damage", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1587,9 +1584,7 @@ private:
|
|||
|
||||
class max_possible_damage_with_retaliation_function : public function_expression {
|
||||
public:
|
||||
max_possible_damage_with_retaliation_function(
|
||||
const args_list& args
|
||||
, const formula_ai& /*ai*/)
|
||||
max_possible_damage_with_retaliation_function(const args_list& args)
|
||||
: function_expression("max_possible_damage_with_retaliation", args, 2, 2)
|
||||
{}
|
||||
private:
|
||||
|
@ -1637,96 +1632,69 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
expression_ptr ai_function_symbol_table::create_function(const std::string &fn,
|
||||
const std::vector<expression_ptr>& args) const {
|
||||
if(fn == "outcomes") {
|
||||
return expression_ptr(new outcomes_function(args, ai_));
|
||||
//} else if(fn == "evaluate_for_position") {
|
||||
// return expression_ptr(new evaluate_for_position_function(args, ai_));
|
||||
} else if(fn == "move") {
|
||||
return expression_ptr(new move_function(args));
|
||||
} else if(fn == "move_partial") {
|
||||
return expression_ptr(new move_partial_function(args));
|
||||
} else if(fn == "attack") {
|
||||
return expression_ptr(new attack_function(args, ai_));
|
||||
} else if(fn == "rate_action") {
|
||||
return expression_ptr(new rate_action_function(args, ai_));
|
||||
} else if(fn == "recall") {
|
||||
return expression_ptr(new recall_function(args));
|
||||
} else if(fn == "recruit") {
|
||||
return expression_ptr(new recruit_function(args));
|
||||
} else if(fn == "safe_call") {
|
||||
return expression_ptr(new safe_call_function(args));
|
||||
} else if(fn == "get_unit_type") {
|
||||
return expression_ptr(new get_unit_type_function(args));
|
||||
} else if(fn == "is_avoided_location") {
|
||||
return expression_ptr(new is_avoided_location_function(args,ai_));
|
||||
} else if(fn == "is_village") {
|
||||
return expression_ptr(new is_village_function(args));
|
||||
} else if(fn == "is_unowned_village") {
|
||||
return expression_ptr(new is_unowned_village_function(args, ai_));
|
||||
} else if(fn == "unit_at") {
|
||||
return expression_ptr(new unit_at_function(args, ai_));
|
||||
} else if(fn == "unit_moves") {
|
||||
return expression_ptr(new unit_moves_function(args, ai_));
|
||||
} else if(fn == "set_var") {
|
||||
return expression_ptr(new set_var_function(args));
|
||||
} else if(fn == "set_unit_var") {
|
||||
return expression_ptr(new set_unit_var_function(args));
|
||||
} else if(fn == "fallback") {
|
||||
return expression_ptr(new fallback_function(args));
|
||||
} else if(fn == "units_can_reach") {
|
||||
return expression_ptr(new units_can_reach_function(args, ai_));
|
||||
} else if(fn == "debug_label") {
|
||||
return expression_ptr(new debug_label_function(args, ai_));
|
||||
} else if(fn == "defense_on") {
|
||||
return expression_ptr(new defense_on_function(args, ai_));
|
||||
} else if(fn == "chance_to_hit") {
|
||||
return expression_ptr(new chance_to_hit_function(args, ai_));
|
||||
} else if(fn == "movement_cost") {
|
||||
return expression_ptr(new movement_cost_function(args, ai_));
|
||||
} else if(fn == "max_possible_damage") {
|
||||
return expression_ptr(new max_possible_damage_function(args, ai_));
|
||||
} else if(fn == "max_possible_damage_with_retaliation") {
|
||||
return expression_ptr(new max_possible_damage_with_retaliation_function(args, ai_));
|
||||
} else if(fn == "next_hop") {
|
||||
return expression_ptr(new next_hop_function(args, ai_));
|
||||
} else if(fn == "adjacent_locs") {
|
||||
return expression_ptr(new adjacent_locs_function(args, ai_));
|
||||
} else if(fn == "locations_in_radius") {
|
||||
return expression_ptr(new locations_in_radius_function(args, ai_));
|
||||
} else if(fn == "castle_locs") {
|
||||
return expression_ptr(new castle_locs_function(args, ai_));
|
||||
} else if(fn == "timeofday_modifier") {
|
||||
return expression_ptr(new timeofday_modifier_function(args, ai_));
|
||||
} else if(fn == "distance_to_nearest_unowned_village") {
|
||||
return expression_ptr(new distance_to_nearest_unowned_village_function(args, ai_));
|
||||
} else if(fn == "shortest_path") {
|
||||
return expression_ptr(new shortest_path_function(args, ai_));
|
||||
} else if(fn == "simplest_path") {
|
||||
return expression_ptr(new simplest_path_function(args, ai_));
|
||||
} else if(fn == "nearest_keep") {
|
||||
return expression_ptr(new nearest_keep_function(args, ai_));
|
||||
} else if(fn == "suitable_keep") {
|
||||
return expression_ptr(new suitable_keep_function(args, ai_));
|
||||
} else if(fn == "nearest_loc") {
|
||||
return expression_ptr(new nearest_loc_function(args, ai_));
|
||||
} else if(fn == "find_shroud") {
|
||||
return expression_ptr(new find_shroud_function(args, ai_));
|
||||
} else if(fn == "close_enemies") {
|
||||
return expression_ptr(new close_enemies_function(args, ai_));
|
||||
} else if(fn == "calculate_outcome") {
|
||||
return expression_ptr(new calculate_outcome_function(args, ai_));
|
||||
} else if(fn == "run_file") {
|
||||
return expression_ptr(new run_file_function(args, ai_));
|
||||
} else if(fn == "calculate_map_ownership") {
|
||||
return expression_ptr(new calculate_map_ownership_function(args, ai_));
|
||||
} else {
|
||||
return function_symbol_table::create_function(fn, args);
|
||||
template<typename T>
|
||||
class ai_formula_function : public formula_function {
|
||||
protected:
|
||||
formula_ai& ai_;
|
||||
public:
|
||||
ai_formula_function(const std::string& name, ai::formula_ai& ai) : formula_function(name), ai_(ai) {}
|
||||
function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const {
|
||||
return function_expression_ptr(new T(args, ai_));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// First macro is for functions taking an additional formula_ai argument.
|
||||
// Functions using the second macro could potentially be made core.
|
||||
#define AI_FUNCTION(name) add_function(#name, formula_function_ptr( \
|
||||
new ai_formula_function<name##_function>(#name, ai)))
|
||||
#define FUNCTION(name) add_function(#name, formula_function_ptr( \
|
||||
new builtin_formula_function<name##_function>(#name)))
|
||||
|
||||
ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) {
|
||||
FUNCTION(outcomes);
|
||||
//AI_FUNCTION(evaluate_for_position);
|
||||
FUNCTION(move);
|
||||
FUNCTION(move_partial);
|
||||
FUNCTION(attack);
|
||||
AI_FUNCTION(rate_action);
|
||||
FUNCTION(recall);
|
||||
FUNCTION(recruit);
|
||||
FUNCTION(safe_call);
|
||||
FUNCTION(get_unit_type);
|
||||
AI_FUNCTION(is_avoided_location);
|
||||
FUNCTION(is_village);
|
||||
AI_FUNCTION(is_unowned_village);
|
||||
FUNCTION(unit_at);
|
||||
AI_FUNCTION(unit_moves);
|
||||
FUNCTION(set_var);
|
||||
FUNCTION(set_unit_var);
|
||||
FUNCTION(fallback);
|
||||
FUNCTION(units_can_reach);
|
||||
AI_FUNCTION(debug_label);
|
||||
FUNCTION(defense_on);
|
||||
FUNCTION(chance_to_hit);
|
||||
FUNCTION(movement_cost);
|
||||
FUNCTION(max_possible_damage);
|
||||
FUNCTION(max_possible_damage_with_retaliation);
|
||||
AI_FUNCTION(next_hop);
|
||||
FUNCTION(adjacent_locs);
|
||||
FUNCTION(locations_in_radius);
|
||||
FUNCTION(castle_locs);
|
||||
FUNCTION(timeofday_modifier);
|
||||
AI_FUNCTION(distance_to_nearest_unowned_village);
|
||||
AI_FUNCTION(shortest_path);
|
||||
AI_FUNCTION(simplest_path);
|
||||
AI_FUNCTION(nearest_keep);
|
||||
AI_FUNCTION(suitable_keep);
|
||||
FUNCTION(nearest_loc);
|
||||
AI_FUNCTION(find_shroud);
|
||||
AI_FUNCTION(close_enemies);
|
||||
FUNCTION(calculate_outcome);
|
||||
AI_FUNCTION(run_file);
|
||||
AI_FUNCTION(calculate_map_ownership);
|
||||
}
|
||||
#undef FUNCTION
|
||||
|
||||
}
|
||||
|
|
|
@ -28,17 +28,7 @@ namespace game_logic {
|
|||
class ai_function_symbol_table : public function_symbol_table {
|
||||
|
||||
public:
|
||||
explicit ai_function_symbol_table(ai::formula_ai& ai) :
|
||||
ai_(ai),
|
||||
move_functions()
|
||||
{}
|
||||
|
||||
expression_ptr create_function(const std::string& fn,
|
||||
const std::vector<expression_ptr>& args) const;
|
||||
|
||||
private:
|
||||
ai::formula_ai& ai_;
|
||||
std::set<std::string> move_functions;
|
||||
explicit ai_function_symbol_table(ai::formula_ai& ai);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
*/
|
||||
|
||||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/function.hpp"
|
||||
#include "units/unit.hpp"
|
||||
#include "units/formula_manager.hpp"
|
||||
#include "config.hpp"
|
||||
|
||||
template <typename T, typename K>
|
||||
variant convert_map( const std::map<T, K>& input_map ) {
|
||||
|
@ -459,6 +461,80 @@ int unit_type_callable::do_compare(const formula_callable* callable) const
|
|||
return u_.id().compare(u_callable->u_.id());
|
||||
}
|
||||
|
||||
class fai_variant_visitor : public boost::static_visitor<variant> {
|
||||
public:
|
||||
variant operator()(bool b) const {return variant(b ? 1 : 0);}
|
||||
variant operator()(int i) const {return variant(i);}
|
||||
variant operator()(unsigned long long i) const {return variant(i);}
|
||||
variant operator()(double i) const {return variant(i * 1000, variant::DECIMAL_VARIANT);}
|
||||
variant operator()(const std::string& s) const {return variant(s);} // TODO: Should comma-separated lists of stuff be returned as a list? The challenge is to distinguish them from ordinary strings that happen to contain a comma (or should we assume that such strings will be translatable?)
|
||||
variant operator()(const t_string& s) const {return variant(s.str());}
|
||||
variant operator()(boost::blank) const {return variant();}
|
||||
};
|
||||
|
||||
variant config_callable::get_value(const std::string& key) const
|
||||
{
|
||||
if(cfg_.has_attribute(key)) {
|
||||
return cfg_[key].apply_visitor(fai_variant_visitor());
|
||||
} else if(cfg_.has_child(key)) {
|
||||
std::vector<variant> result;
|
||||
for(const auto& child : cfg_.child_range(key)) {
|
||||
result.push_back(variant(new config_callable(child)));
|
||||
}
|
||||
return variant(&result);
|
||||
} else if(key == "__all_children") {
|
||||
std::vector<variant> result;
|
||||
for(const auto& child : cfg_.all_children_range()) {
|
||||
const variant cfg_child(new config_callable(child.cfg));
|
||||
const variant kv(new game_logic::key_value_pair(variant(child.key), cfg_child));
|
||||
result.push_back(kv);
|
||||
}
|
||||
return variant(&result);
|
||||
} else if(key == "__children") {
|
||||
std::map<std::string, std::vector<variant> > build;
|
||||
for(const auto& child : cfg_.all_children_range()) {
|
||||
const variant cfg_child(new config_callable(child.cfg));
|
||||
build[child.key].push_back(cfg_child);
|
||||
}
|
||||
std::map<variant,variant> result;
|
||||
for(auto& p : build) {
|
||||
result[variant(p.first)] = variant(&p.second);
|
||||
}
|
||||
return variant(&result);
|
||||
} else if(key == "__attributes") {
|
||||
std::map<variant,variant> result;
|
||||
for(const auto& val : cfg_.attribute_range()) {
|
||||
result[variant(val.first)] = val.second.apply_visitor(fai_variant_visitor());
|
||||
}
|
||||
return variant(&result);
|
||||
} else return variant();
|
||||
}
|
||||
|
||||
void config_callable::get_inputs(std::vector<game_logic::formula_input>* inputs) const
|
||||
{
|
||||
inputs->push_back(game_logic::formula_input("__all_children", game_logic::FORMULA_READ_ONLY));
|
||||
inputs->push_back(game_logic::formula_input("__children", game_logic::FORMULA_READ_ONLY));
|
||||
inputs->push_back(game_logic::formula_input("__attributes", game_logic::FORMULA_READ_ONLY));
|
||||
for(const auto& val : cfg_.attribute_range()) {
|
||||
if(val.first.find_first_not_of(game_logic::formula::id_chars) != std::string::npos) {
|
||||
inputs->push_back(game_logic::formula_input(val.first, game_logic::FORMULA_READ_ONLY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int config_callable::do_compare(const game_logic::formula_callable* callable) const
|
||||
{
|
||||
const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
|
||||
if(cfg_callable == NULL) {
|
||||
return formula_callable::do_compare(callable);
|
||||
}
|
||||
|
||||
if(cfg_ == cfg_callable->get_config()) {
|
||||
return 0;
|
||||
}
|
||||
return cfg_.hash().compare(cfg_callable->get_config().hash());
|
||||
}
|
||||
|
||||
variant terrain_callable::get_value(const std::string& key) const
|
||||
{
|
||||
if(key == "x") {
|
||||
|
|
|
@ -186,6 +186,17 @@ private:
|
|||
const unit_type& u_;
|
||||
};
|
||||
|
||||
class config_callable : public game_logic::formula_callable {
|
||||
public:
|
||||
config_callable(const config& c) : cfg_(c) {}
|
||||
variant get_value(const std::string& key) const;
|
||||
void get_inputs(std::vector<game_logic::formula_input>* inputs) const;
|
||||
int do_compare(const formula_callable* callable) const;
|
||||
const config& get_config() const {return cfg_;}
|
||||
private:
|
||||
const config& cfg_;
|
||||
};
|
||||
|
||||
|
||||
CALLABLE_WRAPPER_START(team)
|
||||
CALLABLE_WRAPPER_INPUT(side)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
namespace game_logic
|
||||
{
|
||||
|
||||
const char*const formula::id_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
|
||||
void formula_callable::set_value(const std::string& key, const variant& /*value*/)
|
||||
{
|
||||
std::cerr << "ERROR: cannot set key '" << key << "' on object" << std::endl;
|
||||
|
@ -1017,10 +1019,11 @@ expression_ptr parse_expression(const token* i1, const token* i2, function_symbo
|
|||
if(symbols == nullptr) {
|
||||
throw formula_error("Function symbol table required but not present", "",*i1->filename, i1->line_number);
|
||||
}
|
||||
symbols->add_formula_function(formula_name,
|
||||
symbols->add_function(formula_name,
|
||||
formula_function_ptr(new user_formula_function(formula_name,
|
||||
const_formula_ptr(new formula(beg, i1, symbols)),
|
||||
formula::create_optional_formula(precond, symbols),
|
||||
args);
|
||||
args)));
|
||||
if((i1 == i2) || (i1 == (i2-1))) {
|
||||
return expression_ptr(new function_list_expression(symbols));
|
||||
}
|
||||
|
@ -1345,6 +1348,7 @@ formula::formula(const std::string& str, function_symbol_table* symbols) :
|
|||
expr_ = expression_ptr(new null_expression());
|
||||
}
|
||||
}
|
||||
|
||||
formula::formula(const token* i1, const token* i2, function_symbol_table* symbols) :
|
||||
expr_(),
|
||||
str_(),
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
~formula();
|
||||
const std::string& str() const { return str_; }
|
||||
|
||||
static const char*const id_chars;
|
||||
private:
|
||||
variant execute(const formula_callable& variables, formula_debugger *fdb = nullptr) const;
|
||||
variant execute(formula_debugger *fdb) const;
|
||||
|
|
|
@ -1447,21 +1447,21 @@ variant formula_function_expression::execute(const formula_callable& variables,
|
|||
return res;
|
||||
}
|
||||
|
||||
function_expression_ptr formula_function::generate_function_expression(const std::vector<expression_ptr>& args) const
|
||||
function_expression_ptr user_formula_function::generate_function_expression(const std::vector<expression_ptr>& args) const
|
||||
{
|
||||
return function_expression_ptr(new formula_function_expression(name_, args, formula_, precondition_, args_));
|
||||
}
|
||||
|
||||
void function_symbol_table::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
|
||||
void function_symbol_table::add_function(const std::string& name, formula_function_ptr fcn)
|
||||
{
|
||||
custom_formulas_[name] = formula_function(name, formula, precondition, args);
|
||||
custom_formulas_[name] = fcn;
|
||||
}
|
||||
|
||||
expression_ptr function_symbol_table::create_function(const std::string& fn, const std::vector<expression_ptr>& args) const
|
||||
{
|
||||
const std::map<std::string, formula_function>::const_iterator i = custom_formulas_.find(fn);
|
||||
const functions_map::const_iterator i = custom_formulas_.find(fn);
|
||||
if(i != custom_formulas_.end()) {
|
||||
return i->second.generate_function_expression(args);
|
||||
return i->second->generate_function_expression(args);
|
||||
}
|
||||
|
||||
return expression_ptr();
|
||||
|
@ -1470,7 +1470,7 @@ expression_ptr function_symbol_table::create_function(const std::string& fn, con
|
|||
std::vector<std::string> function_symbol_table::get_function_names() const
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
for(std::map<std::string, formula_function>::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); ++iter ) {
|
||||
for(functions_map::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); ++iter ) {
|
||||
res.push_back((*iter).first);
|
||||
}
|
||||
return res;
|
||||
|
@ -1478,45 +1478,12 @@ std::vector<std::string> function_symbol_table::get_function_names() const
|
|||
|
||||
namespace {
|
||||
|
||||
class base_function_creator {
|
||||
public:
|
||||
virtual expression_ptr create_function(const std::vector<expression_ptr>& args) const = 0;
|
||||
virtual ~base_function_creator() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class function_creator : public base_function_creator {
|
||||
public:
|
||||
virtual expression_ptr create_function(const std::vector<expression_ptr>& args) const {
|
||||
return expression_ptr(new T(args));
|
||||
}
|
||||
virtual ~function_creator() {}
|
||||
};
|
||||
|
||||
typedef std::map<std::string, base_function_creator*> functions_map;
|
||||
|
||||
// Takes ownership of the pointers, deleting them at program termination to
|
||||
// suppress valgrind false positives
|
||||
struct functions_map_manager {
|
||||
functions_map map_;
|
||||
~functions_map_manager() {
|
||||
for (functions_map::value_type & v : map_) {
|
||||
delete(v.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
functions_map& get_functions_map() {
|
||||
|
||||
static functions_map_manager map_man;
|
||||
functions_map & functions_table = map_man.map_;
|
||||
|
||||
#ifdef HAVE_VISUAL_LEAK_DETECTOR
|
||||
VLDDisable();
|
||||
#endif
|
||||
function_symbol_table& get_functions_map() {
|
||||
static function_symbol_table functions_table;
|
||||
|
||||
if(functions_table.empty()) {
|
||||
#define FUNCTION(name) functions_table[#name] = new function_creator<name##_function>();
|
||||
#define FUNCTION(name) functions_table.add_function(#name, \
|
||||
formula_function_ptr(new builtin_formula_function<name##_function>(#name)))
|
||||
FUNCTION(debug);
|
||||
FUNCTION(dir);
|
||||
FUNCTION(if);
|
||||
|
@ -1525,7 +1492,7 @@ functions_map& get_functions_map() {
|
|||
FUNCTION(min);
|
||||
FUNCTION(max);
|
||||
FUNCTION(choose);
|
||||
FUNCTION(debug_float);
|
||||
FUNCTION(debug_float);
|
||||
FUNCTION(debug_print);
|
||||
FUNCTION(debug_profile);
|
||||
FUNCTION(wave);
|
||||
|
@ -1596,26 +1563,18 @@ expression_ptr create_function(const std::string& fn,
|
|||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
//DBG_NG << "FN: '" << fn << "' " << fn.size() << "\n";
|
||||
|
||||
functions_map::const_iterator i = get_functions_map().find(fn);
|
||||
if(i == get_functions_map().end()) {
|
||||
throw formula_error("Unknow function: " + fn, "", "", 0);
|
||||
}
|
||||
|
||||
return i->second->create_function(args);
|
||||
}
|
||||
|
||||
std::vector<std::string> builtin_function_names()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
const functions_map& m = get_functions_map();
|
||||
for(functions_map::const_iterator i = m.begin(); i != m.end(); ++i) {
|
||||
res.push_back(i->first);
|
||||
|
||||
expression_ptr res(get_functions_map().create_function(fn, args));
|
||||
if(!res) {
|
||||
throw formula_error("Unknown function: " + fn, "", "", 0);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> builtin_function_names()
|
||||
{
|
||||
return get_functions_map().get_function_names();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -96,38 +96,48 @@ private:
|
|||
typedef boost::shared_ptr<function_expression> function_expression_ptr;
|
||||
|
||||
class formula_function {
|
||||
protected:
|
||||
std::string name_;
|
||||
public:
|
||||
formula_function(const std::string name) : name_(name) {}
|
||||
virtual function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const = 0;
|
||||
virtual ~formula_function() {}
|
||||
};
|
||||
|
||||
class user_formula_function : public formula_function {
|
||||
const_formula_ptr formula_;
|
||||
const_formula_ptr precondition_;
|
||||
std::vector<std::string> args_;
|
||||
public:
|
||||
formula_function() :
|
||||
name_(),
|
||||
formula_(),
|
||||
precondition_(),
|
||||
args_()
|
||||
{
|
||||
}
|
||||
|
||||
formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args) : name_(name), formula_(formula), precondition_(precondition), args_(args)
|
||||
user_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
|
||||
: formula_function(name)
|
||||
, formula_(formula)
|
||||
, precondition_(precondition)
|
||||
, args_(args)
|
||||
{}
|
||||
|
||||
function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const;
|
||||
};
|
||||
|
||||
class function_symbol_table {
|
||||
std::map<std::string, formula_function> custom_formulas_;
|
||||
template<typename T>
|
||||
class builtin_formula_function : public formula_function {
|
||||
public:
|
||||
function_symbol_table() :
|
||||
custom_formulas_()
|
||||
{
|
||||
builtin_formula_function(const std::string& name) : formula_function(name) {}
|
||||
function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const {
|
||||
return function_expression_ptr(new T(args));
|
||||
}
|
||||
};
|
||||
|
||||
virtual ~function_symbol_table() {}
|
||||
virtual void add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args);
|
||||
virtual expression_ptr create_function(const std::string& fn,
|
||||
const std::vector<expression_ptr>& args) const;
|
||||
typedef boost::shared_ptr<formula_function> formula_function_ptr;
|
||||
typedef std::map<std::string, formula_function_ptr> functions_map;
|
||||
|
||||
class function_symbol_table {
|
||||
functions_map custom_formulas_;
|
||||
public:
|
||||
void add_function(const std::string& name, formula_function_ptr fcn);
|
||||
expression_ptr create_function(const std::string& fn, const std::vector<expression_ptr>& args) const;
|
||||
std::vector<std::string> get_function_names() const;
|
||||
bool empty() {return custom_formulas_.empty();}
|
||||
};
|
||||
|
||||
expression_ptr create_function(const std::string& fn,
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "scripting/lua_api.hpp" // for luaW_toboolean, etc
|
||||
#include "scripting/lua_common.hpp"
|
||||
#include "scripting/lua_cpp_function.hpp"
|
||||
#include "scripting/lua_formula_bridge.hpp"
|
||||
#include "scripting/lua_gui2.hpp" // for show_gamestate_inspector
|
||||
#include "scripting/lua_pathfind_cost_calculator.hpp"
|
||||
#include "scripting/lua_race.hpp"
|
||||
|
@ -4302,11 +4303,13 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
|
|||
{ "add_known_unit", &intf_add_known_unit },
|
||||
{ "add_modification", &intf_add_modification },
|
||||
{ "advance_unit", &intf_advance_unit },
|
||||
{ "compile_formula", &lua_formula_bridge::intf_compile_formula},
|
||||
{ "copy_unit", &intf_copy_unit },
|
||||
{ "create_unit", &intf_create_unit },
|
||||
{ "debug", &intf_debug },
|
||||
{ "debug_ai", &intf_debug_ai },
|
||||
{ "eval_conditional", &intf_eval_conditional },
|
||||
{ "eval_formula", &lua_formula_bridge::intf_eval_formula},
|
||||
{ "get_era", &intf_get_era },
|
||||
{ "get_image_size", &intf_get_image_size },
|
||||
{ "get_time_stamp", &intf_get_time_stamp },
|
||||
|
@ -4500,6 +4503,9 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
|
|||
lua_pushstring(L, "unit variables");
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Create formula bridge metatables
|
||||
cmd_log_ << lua_formula_bridge::register_metatables(L);
|
||||
|
||||
// Create the vconfig metatable.
|
||||
cmd_log_ << lua_common::register_vconfig_metatable(L);
|
||||
|
|
296
src/scripting/lua_formula_bridge.cpp
Normal file
296
src/scripting/lua_formula_bridge.cpp
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
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 as published by
|
||||
the Free Software Foundation; either version 2 of the License, 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.
|
||||
*/
|
||||
|
||||
#include "scripting/lua_formula_bridge.hpp"
|
||||
|
||||
#include "boost/variant/static_visitor.hpp"
|
||||
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
#include "scripting/lua_api.hpp"
|
||||
#include "scripting/lua_common.hpp"
|
||||
#include "lua/lauxlib.h"
|
||||
#include "lua/lua.h"
|
||||
#include "formula/callable_objects.hpp"
|
||||
#include "formula/formula.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include "resources.hpp"
|
||||
#include "units/map.hpp"
|
||||
|
||||
void luaW_pushfaivariant(lua_State* L, variant val);
|
||||
variant luaW_tofaivariant(lua_State* L, int i);
|
||||
|
||||
using namespace game_logic;
|
||||
|
||||
class lua_callable : public formula_callable {
|
||||
lua_State* mState;
|
||||
int table_i;
|
||||
public:
|
||||
lua_callable(lua_State* L, int i) : mState(L), table_i(lua_absindex(L,i)) {}
|
||||
variant get_value(const std::string& key) const {
|
||||
if(key == "__list") {
|
||||
std::vector<variant> values;
|
||||
size_t n = lua_rawlen(mState, table_i);
|
||||
if(n == 0) {
|
||||
return variant();
|
||||
}
|
||||
for(size_t i = 1; i <= n; i++) {
|
||||
lua_pushinteger(mState, i);
|
||||
lua_gettable(mState, table_i);
|
||||
values.push_back(luaW_tofaivariant(mState, -1));
|
||||
}
|
||||
return variant(&values);
|
||||
} else if(key == "__map") {
|
||||
std::map<variant,variant> values;
|
||||
for(lua_pushnil(mState); lua_next(mState, table_i); lua_pop(mState, 1)) {
|
||||
values[luaW_tofaivariant(mState, -2)] = luaW_tofaivariant(mState, -1);
|
||||
}
|
||||
return variant(&values);
|
||||
}
|
||||
lua_pushlstring(mState, key.c_str(), key.size());
|
||||
lua_gettable(mState, table_i);
|
||||
variant result = luaW_tofaivariant(mState, -1);
|
||||
lua_pop(mState, 1);
|
||||
return result;
|
||||
}
|
||||
void get_inputs(std::vector<formula_input>* inputs) const {
|
||||
inputs->push_back(formula_input("__list", FORMULA_READ_ONLY));
|
||||
inputs->push_back(formula_input("__map", FORMULA_READ_ONLY));
|
||||
for(lua_pushnil(mState); lua_next(mState, table_i); lua_pop(mState,1)) {
|
||||
if(lua_isstring(mState, -2) && !lua_isnumber(mState, -2)) {
|
||||
std::string key = lua_tostring(mState, -2);
|
||||
if(key.find_first_not_of(formula::id_chars) != std::string::npos) {
|
||||
inputs->push_back(formula_input(key, FORMULA_READ_ONLY));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int do_compare(const formula_callable* other) const {
|
||||
const lua_callable* lua = dynamic_cast<const lua_callable*>(other);
|
||||
if(lua == NULL) {
|
||||
return formula_callable::do_compare(other);
|
||||
}
|
||||
if(mState == lua->mState) { // Which should always be the case, but let's be safe here
|
||||
if(lua_compare(mState, table_i, lua->table_i, LUA_OPEQ)) {
|
||||
return 0;
|
||||
}
|
||||
int top = lua_gettop(mState);
|
||||
if(lua_getmetatable(mState, table_i)) {
|
||||
lua_getfield(mState, -1, "__lt");
|
||||
if(!lua_isnoneornil(mState, -1)) {
|
||||
if(lua_getmetatable(mState, lua->table_i)) {
|
||||
lua_getfield(mState, -1, "__lt");
|
||||
if(!lua_isnoneornil(mState, -1)) {
|
||||
lua_settop(mState, top);
|
||||
return lua_compare(mState, table_i, lua->table_i, LUA_OPLT) ? -1 : 1;
|
||||
}
|
||||
if(lua_compare(mState, -4, -2, LUA_OPEQ)) {
|
||||
lua_settop(mState, top);
|
||||
return 0;
|
||||
}
|
||||
const void* lhs = lua_topointer(mState, -4);
|
||||
const void* rhs = lua_topointer(mState, -2);
|
||||
lua_settop(mState, top);
|
||||
return lhs < rhs ? -1 : (lhs > rhs ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_settop(mState, top);
|
||||
return lua_topointer(mState, -2) < lua_topointer(mState, -1) ? -1 : 1;
|
||||
}
|
||||
return mState < lua->mState ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
void luaW_pushfaivariant(lua_State* L, variant val) {
|
||||
if(val.is_int()) {
|
||||
lua_pushinteger(L, val.as_int());
|
||||
} else if(val.is_decimal()) {
|
||||
lua_pushnumber(L, val.as_decimal() / 1000.0);
|
||||
} else if(val.is_string()) {
|
||||
const std::string result_string = val.as_string();
|
||||
lua_pushlstring(L, result_string.c_str(), result_string.size());
|
||||
} else if(val.is_list()) {
|
||||
lua_newtable(L);
|
||||
for(const variant& v : val.as_list()) {
|
||||
lua_pushinteger(L, lua_rawlen(L, -1) + 1);
|
||||
luaW_pushfaivariant(L, v);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
} else if(val.is_map()) {
|
||||
typedef std::map<variant,variant>::value_type kv_type;
|
||||
lua_newtable(L);
|
||||
for(const kv_type& v : val.as_map()) {
|
||||
luaW_pushfaivariant(L, v.first);
|
||||
luaW_pushfaivariant(L, v.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
} else if(val.is_callable()) {
|
||||
// First try a few special cases
|
||||
if(unit_callable* u_ref = val.try_convert<unit_callable>()) {
|
||||
const unit& u = u_ref->get_unit();
|
||||
unit_map::iterator un_it = resources::units->find(u.get_location());
|
||||
if(&*un_it == &u) {
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.underlying_id());
|
||||
} else {
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u.side(), u.underlying_id());
|
||||
}
|
||||
lua_pushlightuserdata(L, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
} else if(location_callable* loc_ref = val.try_convert<location_callable>()) {
|
||||
luaW_pushlocation(L, loc_ref->loc());
|
||||
} else {
|
||||
// If those fail, convert generically to a map
|
||||
const formula_callable* obj = val.as_callable();
|
||||
std::vector<formula_input> inputs;
|
||||
obj->get_inputs(&inputs);
|
||||
lua_newtable(L);
|
||||
for(const formula_input& attr : inputs) {
|
||||
if(attr.access == FORMULA_WRITE_ONLY) {
|
||||
continue;
|
||||
}
|
||||
lua_pushstring(L, attr.name.c_str());
|
||||
luaW_pushfaivariant(L, obj->query_value(attr.name));
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
} else if(val.is_null()) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
}
|
||||
|
||||
variant luaW_tofaivariant(lua_State* L, int i) {
|
||||
switch(lua_type(L, i)) {
|
||||
case LUA_TBOOLEAN:
|
||||
return variant(lua_tointeger(L, i));
|
||||
case LUA_TNUMBER:
|
||||
return variant(lua_tonumber(L, i), variant::DECIMAL_VARIANT);
|
||||
case LUA_TSTRING:
|
||||
return variant(lua_tostring(L, i));
|
||||
case LUA_TTABLE:
|
||||
return variant(new lua_callable(L, i));
|
||||
case LUA_TUSERDATA:
|
||||
static t_string tstr;
|
||||
static vconfig vcfg = vconfig::unconstructed_vconfig();
|
||||
static map_location loc;
|
||||
if(luaW_totstring(L, i, tstr)) {
|
||||
return variant(tstr.str());
|
||||
} else if(luaW_tovconfig(L, i, vcfg)) {
|
||||
return variant(new config_callable(vcfg.get_parsed_config()));
|
||||
} else if(unit* u = luaW_tounit(L, i)) {
|
||||
return variant(new unit_callable(*u));
|
||||
} else if(luaW_tolocation(L, i, loc)) {
|
||||
return variant(new location_callable(loc));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return variant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a formula in the formula engine.
|
||||
* - Arg 1: Formula string.
|
||||
* - Arg 2: optional context; can be a unit or a Lua table.
|
||||
* - Ret 1: Result of the formula.
|
||||
*/
|
||||
int lua_formula_bridge::intf_eval_formula(lua_State *L)
|
||||
{
|
||||
bool need_delete = false;
|
||||
fwrapper* form;
|
||||
if(luaW_hasmetatable(L, 1, formulaKey)) {
|
||||
form = static_cast<fwrapper*>(lua_touserdata(L, 1));
|
||||
} else {
|
||||
need_delete = true;
|
||||
form = new fwrapper(luaL_checkstring(L, 1));
|
||||
}
|
||||
boost::shared_ptr<formula_callable> context, fallback;
|
||||
if(unit* u = luaW_tounit(L, 2)) {
|
||||
context.reset(new unit_callable(*u));
|
||||
} else if(lua_istable(L, 2)) {
|
||||
context.reset(new lua_callable(L, 2));
|
||||
} else {
|
||||
context.reset(new map_formula_callable);
|
||||
}
|
||||
variant result = form->evaluate(*context);
|
||||
luaW_pushfaivariant(L, result);
|
||||
if(need_delete) {
|
||||
delete form;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_formula_bridge::intf_compile_formula(lua_State* L)
|
||||
{
|
||||
if(!lua_isstring(L, 1)) {
|
||||
luaL_typerror(L, 1, "string");
|
||||
}
|
||||
new(lua_newuserdata(L, sizeof(fwrapper))) fwrapper(lua_tostring(L, 1));
|
||||
lua_pushlightuserdata(L, formulaKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_formula_bridge::fwrapper::fwrapper(const std::string& code, game_logic::function_symbol_table* functions)
|
||||
: formula_ptr(new formula(code, functions))
|
||||
{
|
||||
}
|
||||
|
||||
std::string lua_formula_bridge::fwrapper::str() const
|
||||
{
|
||||
if(formula_ptr) {
|
||||
return formula_ptr->str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
variant lua_formula_bridge::fwrapper::evaluate(const formula_callable& variables, formula_debugger* fdb) const
|
||||
{
|
||||
if(formula_ptr) {
|
||||
return formula_ptr->evaluate(variables, fdb);
|
||||
}
|
||||
return variant();
|
||||
}
|
||||
|
||||
static int impl_formula_collect(lua_State* L)
|
||||
{
|
||||
lua_formula_bridge::fwrapper* form = static_cast<lua_formula_bridge::fwrapper*>(lua_touserdata(L, 1));
|
||||
form->~fwrapper();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int impl_formula_tostring(lua_State* L)
|
||||
{
|
||||
lua_formula_bridge::fwrapper* form = static_cast<lua_formula_bridge::fwrapper*>(lua_touserdata(L, 1));
|
||||
const std::string str = form->str();
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string lua_formula_bridge::register_metatables(lua_State* L)
|
||||
{
|
||||
lua_pushlightuserdata(L, formulaKey);
|
||||
lua_createtable(L, 0, 4);
|
||||
lua_pushcfunction(L, impl_formula_collect);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushcfunction(L, impl_formula_tostring);
|
||||
lua_setfield(L, -2, "__tostring");
|
||||
lua_pushcfunction(L, intf_eval_formula);
|
||||
lua_setfield(L, -2, "__call");
|
||||
lua_pushstring(L, "formula");
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
return "Adding formula metatable...";
|
||||
}
|
46
src/scripting/lua_formula_bridge.hpp
Normal file
46
src/scripting/lua_formula_bridge.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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 as published by
|
||||
the Free Software Foundation; either version 2 of the License, 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 LUA_FORMULA_BRIDGE_HPP_INCLUDED
|
||||
#define LUA_FORMULA_BRIDGE_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class variant;
|
||||
namespace game_logic {
|
||||
class formula;
|
||||
class function_symbol_table;
|
||||
class formula_debugger;
|
||||
class formula_callable;
|
||||
}
|
||||
|
||||
namespace lua_formula_bridge {
|
||||
|
||||
int intf_eval_formula(lua_State*);
|
||||
int intf_compile_formula(lua_State*);
|
||||
std::string register_metatables(lua_State*);
|
||||
|
||||
class fwrapper {
|
||||
boost::shared_ptr<game_logic::formula> formula_ptr;
|
||||
public:
|
||||
fwrapper(const std::string& code, game_logic::function_symbol_table* functions = NULL);
|
||||
std::string str() const;
|
||||
variant evaluate(const game_logic::formula_callable& variables, game_logic::formula_debugger* fdb = NULL) const;
|
||||
};
|
||||
|
||||
} // end namespace lua_formula_bridge
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@ static char const v_unitvarKey = 0;
|
|||
static char const v_ustatusKey = 0;
|
||||
static char const v_uattacksKey = 0;
|
||||
static char const v_uattackKey = 0;
|
||||
static char const v_formulaKey = 0;
|
||||
|
||||
|
||||
luatypekey const executeKey = static_cast<void *>(const_cast<char *>(&v_executeKey));
|
||||
|
@ -29,3 +30,4 @@ luatypekey const unitvarKey = static_cast<void *>(const_cast<char *>(&v_unitvarK
|
|||
luatypekey const ustatusKey = static_cast<void *>(const_cast<char *>(&v_ustatusKey));
|
||||
luatypekey const uattacksKey = static_cast<void *>(const_cast<char *>(&v_uattacksKey));
|
||||
luatypekey const uattackKey = static_cast<void *>(const_cast<char *>(&v_uattackKey));
|
||||
luatypekey const formulaKey = static_cast<void *>(const_cast<char *>(&v_formulaKey));
|
||||
|
|
|
@ -25,5 +25,6 @@ extern luatypekey const unitvarKey;
|
|||
extern luatypekey const ustatusKey;
|
||||
extern luatypekey const uattacksKey;
|
||||
extern luatypekey const uattackKey;
|
||||
extern luatypekey const formulaKey;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue