Skip to content

Commit

Permalink
Lua API: Add wesnoth.compile_formula which returns a callable userdata
Browse files Browse the repository at this point in the history
  • Loading branch information
CelticMinstrel committed Apr 2, 2016
1 parent ac44790 commit 5bb6c30
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -4257,6 +4257,7 @@ 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 },
Expand Down Expand Up @@ -4455,6 +4456,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);
Expand Down
81 changes: 76 additions & 5 deletions src/scripting/lua_formula_bridge.cpp
Expand Up @@ -201,11 +201,14 @@ variant luaW_tofaivariant(lua_State* L, int i) {
*/
int lua_formula_bridge::intf_eval_formula(lua_State *L)
{
using namespace game_logic;
if(!lua_isstring(L, 1)) {
luaL_typerror(L, 1, "string");
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));
}
const formula form(lua_tostring(L, 1));
boost::shared_ptr<formula_callable> context, fallback;
if(unit* u = luaW_tounit(L, 2)) {
context.reset(new unit_callable(*u));
Expand All @@ -214,7 +217,75 @@ int lua_formula_bridge::intf_eval_formula(lua_State *L)
} else {
context.reset(new map_formula_callable);
}
variant result = form.evaluate(*context);
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...";
}
21 changes: 21 additions & 0 deletions src/scripting/lua_formula_bridge.hpp
Expand Up @@ -14,11 +14,32 @@
#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

Expand Down
2 changes: 2 additions & 0 deletions src/scripting/lua_types.cpp
Expand Up @@ -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));
Expand All @@ -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));
1 change: 1 addition & 0 deletions src/scripting/lua_types.hpp
Expand Up @@ -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

0 comments on commit 5bb6c30

Please sign in to comment.