[Lua.MapGen] Formula map filters now support taking precompiled formulas instead of a formula string.

This commit is contained in:
Celtic Minstrel 2024-02-06 21:37:31 -05:00 committed by Celtic Minstrel
parent f22f13f850
commit 5ed7f63ede
3 changed files with 29 additions and 19 deletions

View file

@ -217,6 +217,28 @@ variant luaW_tofaivariant(lua_State* L, int i) {
return variant();
}
/**
* Get a formula from the stack. If @a allow_str is true, it compiles a formula string if found.
* Otherwise, it must be an already-compiled formula.
* Raises an error if a formula is not found, or if there's an error in compilation.
* Thus, it never returns a null pointer.
*/
lua_formula_bridge::fpointer luaW_check_formula(lua_State* L, int idx, bool allow_str) {
using namespace lua_formula_bridge;
fpointer form;
if(void* ud = luaL_testudata(L, idx, formulaKey)) {
form.get_deleter() = [](fwrapper*) {};
form.reset(static_cast<fwrapper*>(ud));
// Setting a no-op deleter guarantees the Lua-held object is not deleted
} else if(allow_str) {
form.reset(new fwrapper(luaL_checkstring(L, idx)));
// Leave deleter at default so it's deleted properly later
} else {
luaW_type_error(L, idx, "formula");
}
return form;
}
/**
* Evaluates a formula in the formula engine.
* - Arg 1: Formula string.
@ -225,14 +247,7 @@ variant luaW_tofaivariant(lua_State* L, int i) {
*/
int lua_formula_bridge::intf_eval_formula(lua_State *L)
{
bool need_delete = false;
fwrapper* form;
if(void* ud = luaL_testudata(L, 1, formulaKey)) {
form = static_cast<fwrapper*>(ud);
} else {
need_delete = true;
form = new fwrapper(luaL_checkstring(L, 1));
}
fpointer form = luaW_check_formula(L, 1, true);
std::shared_ptr<formula_callable> context, fallback;
if(unit* u = luaW_tounit(L, 2)) {
context.reset(new unit_callable(*u));
@ -249,9 +264,6 @@ int lua_formula_bridge::intf_eval_formula(lua_State *L)
}
variant result = form->evaluate(*context);
luaW_pushfaivariant(L, result);
if(need_delete) {
delete form;
}
return 1;
}

View file

@ -14,6 +14,7 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
@ -41,4 +42,6 @@ namespace lua_formula_bridge {
wfl::variant evaluate(const wfl::formula_callable& variables, wfl::formula_debugger* fdb = nullptr) const;
};
using fpointer = std::unique_ptr<fwrapper, std::function<void(fwrapper*)>>;
} // end namespace lua_formula_bridge
lua_formula_bridge::fpointer luaW_check_formula(lua_State* L, int idx, bool allow_str);

View file

@ -22,6 +22,7 @@
#include "map/map.hpp"
#include "pathutils_impl.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_formula_bridge.hpp"
#include "scripting/push_check.hpp"
#include "serialization/string_utils.hpp"
@ -548,14 +549,8 @@ public:
{
LOG_LMG << "creating formula filter";
lua_geti(L, -1, 2);
std::string code = std::string(luaW_tostring(L, -1));
formula_ = luaW_check_formula(L, 1, true);
lua_pop(L, 1);
try {
formula_ = std::make_unique<wfl::formula>(code);
} catch(const wfl::formula_error& e) {
ERR_LMG << "formula error" << e.what();
}
}
bool matches(const gamemap_base&, map_location l) override
{
@ -569,7 +564,7 @@ public:
return false;
}
}
std::unique_ptr<wfl::formula> formula_;
lua_formula_bridge::fpointer formula_;
};
// todo: maybe invent a general macro for this string_switch implementation.