297 lines
6.3 KiB
C++
297 lines
6.3 KiB
C++
#include <lua.hpp>
|
|
#include <sand/sand.h>
|
|
#include <string>
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr char TYPE_BUILDER_MT[] = "lsand.type_builder";
|
|
constexpr char RULE_BUILDER_MT[] = "lsand.rule_builder";
|
|
constexpr char RULE_MT[] = "lsand.rule";
|
|
constexpr char SAND_MT[] = "lsand.sand";
|
|
|
|
sand::type::builder& check_type_builder(lua_State* L, int index)
|
|
{
|
|
return *(sand::type::builder*)luaL_checkudata(L, index, TYPE_BUILDER_MT);
|
|
}
|
|
|
|
sand::rule::builder& check_rule_builder(lua_State* L, int index)
|
|
{
|
|
return *(sand::rule::builder*)luaL_checkudata(L, index, RULE_BUILDER_MT);
|
|
}
|
|
|
|
sand::rule& check_rule(lua_State* L, int index)
|
|
{
|
|
return *(sand::rule*)luaL_checkudata(L, index, RULE_MT);
|
|
}
|
|
|
|
sand::sand& check_sand(lua_State* L, int index)
|
|
{
|
|
return *(sand::sand*)luaL_checkudata(L, index, SAND_MT);
|
|
}
|
|
|
|
int l_type_builder_gc(lua_State* L)
|
|
{
|
|
auto& tb = check_type_builder(L, 1);
|
|
tb.~builder();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_type_builder_assign(lua_State* L)
|
|
{
|
|
auto& tb = check_type_builder(L, 1);
|
|
sand::type t = tb.assign();
|
|
|
|
lua_pushinteger(L, t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int l_type_builder_set_default_conversion(lua_State* L)
|
|
{
|
|
auto& tb = check_type_builder(L, 1);
|
|
auto from = sand::type(luaL_checkinteger(L, 2));
|
|
auto to = sand::type(luaL_checkinteger(L, 3));
|
|
|
|
tb.set_default_conversion(to, from);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_type_builder_build(lua_State* L)
|
|
{
|
|
auto& tb = check_type_builder(L, 1);
|
|
auto* rb
|
|
= (sand::rule::builder*)lua_newuserdata(L, sizeof(sand::rule::builder));
|
|
luaL_getmetatable(L, RULE_BUILDER_MT);
|
|
lua_setmetatable(L, -2);
|
|
|
|
new (rb) sand::rule::builder(tb.build());
|
|
|
|
return 1;
|
|
}
|
|
|
|
int l_rule_builder_gc(lua_State* L)
|
|
{
|
|
auto& rb = check_rule_builder(L, 1);
|
|
rb.~builder();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_rule_builder_add_rule(lua_State* L)
|
|
{
|
|
auto& rb = check_rule_builder(L, 1);
|
|
auto from = sand::type(luaL_checkinteger(L, 2));
|
|
auto to = sand::type(luaL_checkinteger(L, 3));
|
|
|
|
auto* rule = (sand::rule*)lua_newuserdata(L, sizeof(sand::rule));
|
|
luaL_getmetatable(L, RULE_MT);
|
|
lua_setmetatable(L, -2);
|
|
|
|
new (rule) sand::rule(rb.add_rule(from, to));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int l_rule_builder_build(lua_State* L)
|
|
{
|
|
auto& rb = check_rule_builder(L, 1);
|
|
int width = luaL_checkinteger(L, 2);
|
|
int height = luaL_checkinteger(L, 3);
|
|
|
|
auto* sand_object = (sand::sand*)lua_newuserdata(L, sizeof(sand::sand));
|
|
luaL_getmetatable(L, SAND_MT);
|
|
lua_setmetatable(L, -2);
|
|
|
|
new (sand_object) sand::sand(rb.build(width, height, sand::type(1)));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int l_rule_match(lua_State* L)
|
|
{
|
|
auto& r = check_rule(L, 1);
|
|
std::string match_position = luaL_checkstring(L, 2);
|
|
luaL_checktype(L, 3, LUA_TFUNCTION);
|
|
|
|
int fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
const auto& match_fn = [L, fn_ref](auto t) -> bool
|
|
{
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, fn_ref);
|
|
lua_pushinteger(L, t);
|
|
if (lua_pcall(L, 1, 1, 0) != LUA_OK)
|
|
{
|
|
const char* msg = lua_tostring(L, -1);
|
|
lua_pop(L, 1);
|
|
luaL_error(L, "Error during match callback: %s", msg);
|
|
}
|
|
if (!lua_isboolean(L, -1))
|
|
{
|
|
luaL_error(L, "match callback did not return a boolean");
|
|
}
|
|
bool value = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
return value;
|
|
};
|
|
|
|
if (match_position == "top_left")
|
|
{
|
|
r.top_left(match_fn);
|
|
}
|
|
else if (match_position == "top")
|
|
{
|
|
r.top(match_fn);
|
|
}
|
|
else if (match_position == "top_right")
|
|
{
|
|
r.top_right(match_fn);
|
|
}
|
|
else if (match_position == "left")
|
|
{
|
|
r.left(match_fn);
|
|
}
|
|
else if (match_position == "right")
|
|
{
|
|
r.right(match_fn);
|
|
}
|
|
else if (match_position == "bottom_left")
|
|
{
|
|
r.bottom_left(match_fn);
|
|
}
|
|
else if (match_position == "bottom")
|
|
{
|
|
r.bottom(match_fn);
|
|
}
|
|
else if (match_position == "bottom_right")
|
|
{
|
|
r.bottom_right(match_fn);
|
|
}
|
|
else
|
|
{
|
|
luaL_argerror(L, 2, "Invalid match position");
|
|
}
|
|
|
|
lua_pushvalue(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
int l_rule_finish(lua_State* L)
|
|
{
|
|
auto& r = check_rule(L, 1);
|
|
r.~rule();
|
|
|
|
// mark rule as an invalid object
|
|
// will error if any other methods
|
|
// are called on this object
|
|
lua_pushnil(L);
|
|
lua_setmetatable(L, -1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_sand_gc(lua_State* L)
|
|
{
|
|
auto& sand = check_sand(L, 1);
|
|
sand.~sand();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_sand_tick(lua_State* L)
|
|
{
|
|
auto& sand = check_sand(L, 1);
|
|
sand.tick();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int l_sand_get(lua_State* L)
|
|
{
|
|
auto& sand = check_sand(L, 1);
|
|
int x = luaL_checkinteger(L, 2);
|
|
int y = luaL_checkinteger(L, 3);
|
|
|
|
lua_pushinteger(L, sand.get(x, y));
|
|
return 1;
|
|
}
|
|
|
|
int l_sand_set(lua_State* L)
|
|
{
|
|
auto& sand = check_sand(L, 1);
|
|
int x = luaL_checkinteger(L, 2);
|
|
int y = luaL_checkinteger(L, 3);
|
|
sand::type t = sand::type(luaL_checkinteger(L, 4));
|
|
|
|
sand.set(x, y, t);
|
|
return 0;
|
|
}
|
|
|
|
int l_lsand_new(lua_State* L)
|
|
{
|
|
auto* tb
|
|
= (sand::type::builder*)lua_newuserdata(L, sizeof(sand::type::builder));
|
|
luaL_getmetatable(L, TYPE_BUILDER_MT);
|
|
lua_setmetatable(L, -2);
|
|
|
|
new (tb) sand::type::builder();
|
|
|
|
return 1;
|
|
}
|
|
|
|
constexpr luaL_Reg TYPE_BUILDER_FUNCS[]
|
|
= { "__gc",
|
|
l_type_builder_gc,
|
|
"assign",
|
|
l_type_builder_assign,
|
|
"set_default_conversion",
|
|
l_type_builder_set_default_conversion,
|
|
"build",
|
|
l_type_builder_build,
|
|
nullptr,
|
|
nullptr };
|
|
|
|
constexpr luaL_Reg RULE_BUILDER_FUNCS[]
|
|
= { "__gc", l_rule_builder_gc, "add_rule", l_rule_builder_add_rule,
|
|
"build", l_rule_builder_build, nullptr, nullptr };
|
|
|
|
constexpr luaL_Reg RULE_FUNCS[]
|
|
= { "match", l_rule_match, "finish", l_rule_finish, nullptr, nullptr };
|
|
|
|
constexpr luaL_Reg SAND_FUNCS[]
|
|
= { "__gc", l_sand_gc, "tick", l_sand_tick, "get",
|
|
l_sand_get, "set", l_sand_set, nullptr, nullptr };
|
|
|
|
constexpr luaL_Reg LSAND_FUNCS[] = { "new", l_lsand_new, nullptr, nullptr };
|
|
|
|
} // namespace
|
|
|
|
extern "C" int luaopen_lsand(lua_State* L)
|
|
{
|
|
luaL_newmetatable(L, TYPE_BUILDER_MT);
|
|
luaL_register(L, nullptr, TYPE_BUILDER_FUNCS);
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
luaL_newmetatable(L, RULE_BUILDER_MT);
|
|
luaL_register(L, nullptr, RULE_BUILDER_FUNCS);
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
luaL_newmetatable(L, RULE_MT);
|
|
luaL_register(L, nullptr, RULE_FUNCS);
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
luaL_newmetatable(L, SAND_MT);
|
|
luaL_register(L, nullptr, SAND_FUNCS);
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
luaL_openlib(L, "lsand", LSAND_FUNCS, 0);
|
|
|
|
return 1;
|
|
}
|