|
|
|
@ -14,15 +14,19 @@
|
|
|
|
|
|
|
|
|
|
#include "scripting/lua_formula_bridge.hpp"
|
|
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
|
|
#include "game_board.hpp"
|
|
|
|
|
#include "scripting/lua_unit.hpp"
|
|
|
|
|
#include "scripting/lua_common.hpp"
|
|
|
|
|
#include "scripting/lua_kernel_base.hpp"
|
|
|
|
|
#include "scripting/lua_team.hpp"
|
|
|
|
|
#include "scripting/lua_unit_attacks.hpp"
|
|
|
|
|
#include "scripting/lua_unit_type.hpp"
|
|
|
|
|
#include "lua/wrapper_lauxlib.h"
|
|
|
|
|
#include "formula/callable_objects.hpp"
|
|
|
|
|
#include "formula/formula.hpp"
|
|
|
|
|
#include "formula/function.hpp"
|
|
|
|
|
#include "variable.hpp"
|
|
|
|
|
|
|
|
|
|
#include "resources.hpp"
|
|
|
|
@ -30,17 +34,33 @@
|
|
|
|
|
#include "units/unit.hpp"
|
|
|
|
|
|
|
|
|
|
static const char formulaKey[] = "formula";
|
|
|
|
|
static const char formfcntbKey[] = "formula function table";
|
|
|
|
|
|
|
|
|
|
using namespace wfl;
|
|
|
|
|
|
|
|
|
|
void luaW_pushfaivariant(lua_State* L, variant val);
|
|
|
|
|
variant luaW_tofaivariant(lua_State* L, int i);
|
|
|
|
|
|
|
|
|
|
typedef function_symbol_table* functionstb_ptr;
|
|
|
|
|
|
|
|
|
|
std::set<functionstb_ptr> lua_owned_fcntb;
|
|
|
|
|
|
|
|
|
|
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)) {}
|
|
|
|
|
bool is_list() const {
|
|
|
|
|
for(lua_pushnil(mState); lua_next(mState, table_i); lua_pop(mState, 1)) {
|
|
|
|
|
if(!lua_isnumber(mState, -1)) {
|
|
|
|
|
lua_pop(mState, 2);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
lua_callable(lua_State* L, int i) : mState(L), table_i(lua_absindex(L,i)) {
|
|
|
|
|
luaL_checktype(L, i, LUA_TTABLE);
|
|
|
|
|
}
|
|
|
|
|
variant get_value(const std::string& key) const {
|
|
|
|
|
if(key == "__list") {
|
|
|
|
|
std::vector<variant> values;
|
|
|
|
@ -76,7 +96,7 @@ public:
|
|
|
|
|
lua_pop(mState, 1);
|
|
|
|
|
if(is_valid_key) {
|
|
|
|
|
std::string key = lua_tostring(mState, -2);
|
|
|
|
|
if(key.find_first_not_of(formula::id_chars) != std::string::npos) {
|
|
|
|
|
if(key.find_first_not_of(formula::id_chars) == std::string::npos) {
|
|
|
|
|
add_input(inputs, key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -119,6 +139,75 @@ public:
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class lua_formula_function : public function_expression {
|
|
|
|
|
lua_kernel_base& kernel;
|
|
|
|
|
const void* registry_index;
|
|
|
|
|
variant execute(const formula_callable& variables, formula_debugger *fdb) const {
|
|
|
|
|
lua_State* L = kernel.get_state();
|
|
|
|
|
lua_rawgetp(L, LUA_REGISTRYINDEX, registry_index);
|
|
|
|
|
luaW_pushfaivariant(L, variant(variables.fake_ptr()));
|
|
|
|
|
for(auto arg : args()) {
|
|
|
|
|
if(fdb) {
|
|
|
|
|
arg.reset(new wrapper_formula(arg));
|
|
|
|
|
}
|
|
|
|
|
new(L) lua_formula_bridge::fwrapper(arg);
|
|
|
|
|
luaL_setmetatable(L, formulaKey);
|
|
|
|
|
}
|
|
|
|
|
bool success = luaW_pcall(L, args().size() + 1, 2);
|
|
|
|
|
variant result;
|
|
|
|
|
if(!success || lua_isnoneornil(L, -2)) {
|
|
|
|
|
return result;
|
|
|
|
|
} else if(lua_isnoneornil(L, -1)) {
|
|
|
|
|
// Use normal guessing to determine the type
|
|
|
|
|
result = luaW_tofaivariant(L, -2);
|
|
|
|
|
} else {
|
|
|
|
|
std::string type = lua_tostring(L, -1);
|
|
|
|
|
if(type == "string") {
|
|
|
|
|
result = variant(luaL_checkstring(L, -2));
|
|
|
|
|
} else if(type == "integer") {
|
|
|
|
|
result = variant(luaL_checkinteger(L, -2));
|
|
|
|
|
} else if(type == "decimal") {
|
|
|
|
|
result = variant(luaL_checknumber(L, -2), variant::DECIMAL_VARIANT);
|
|
|
|
|
} else if(type == "list") {
|
|
|
|
|
result = lua_callable(L, -2).get_value("__list");
|
|
|
|
|
} else if(type == "map") {
|
|
|
|
|
result = lua_callable(L, -2).get_value("__map");
|
|
|
|
|
} else if(type == "unit") {
|
|
|
|
|
unit& u = luaW_checkunit(L, -2);
|
|
|
|
|
result = variant(std::make_shared<unit_callable>(u));
|
|
|
|
|
} else if(type == "loc") {
|
|
|
|
|
map_location loc = luaW_checklocation(L, -2);
|
|
|
|
|
result = variant(std::make_shared<location_callable>(loc));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
lua_formula_function(const std::string name, const args_list& args, int min_args, int max_args, const void* ridx, lua_kernel_base& k)
|
|
|
|
|
: function_expression(name, args, min_args, max_args)
|
|
|
|
|
, kernel(k)
|
|
|
|
|
, registry_index(ridx)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class lua_formula_function_defn : public formula_function {
|
|
|
|
|
int min_args, max_args;
|
|
|
|
|
lua_kernel_base& kernel;
|
|
|
|
|
public:
|
|
|
|
|
lua_formula_function_defn(const std::string name, int min, int max, lua_kernel_base& k)
|
|
|
|
|
: formula_function(name)
|
|
|
|
|
, min_args(min)
|
|
|
|
|
, max_args(max)
|
|
|
|
|
, kernel(k)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
virtual function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const {
|
|
|
|
|
return function_expression_ptr(new lua_formula_function(name_, args, min_args, max_args, this, kernel));
|
|
|
|
|
}
|
|
|
|
|
virtual ~lua_formula_function_defn() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void luaW_pushfaivariant(lua_State* L, variant val) {
|
|
|
|
|
if(val.is_int()) {
|
|
|
|
|
lua_pushinteger(L, val.as_int());
|
|
|
|
@ -188,6 +277,7 @@ variant luaW_tofaivariant(lua_State* L, int i) {
|
|
|
|
|
case LUA_TBOOLEAN:
|
|
|
|
|
return variant(lua_tointeger(L, i));
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
|
if(lua_isinteger(L, i)) return variant(lua_tointeger(L, i));
|
|
|
|
|
return variant(lua_tonumber(L, i), variant::DECIMAL_VARIANT);
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
|
return variant(lua_tostring(L, i));
|
|
|
|
@ -242,7 +332,7 @@ lua_formula_bridge::fpointer luaW_check_formula(lua_State* L, int idx, bool allo
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Evaluates a formula in the formula engine.
|
|
|
|
|
* - Arg 1: Formula string.
|
|
|
|
|
* - Arg 1: Formula string or object.
|
|
|
|
|
* - Arg 2: optional context; can be a unit or a Lua table.
|
|
|
|
|
* - Ret 1: Result of the formula.
|
|
|
|
|
*/
|
|
|
|
@ -273,7 +363,25 @@ int lua_formula_bridge::intf_compile_formula(lua_State* L)
|
|
|
|
|
if(!lua_isstring(L, 1)) {
|
|
|
|
|
luaW_type_error(L, 1, "string");
|
|
|
|
|
}
|
|
|
|
|
new(L) fwrapper(lua_tostring(L, 1));
|
|
|
|
|
functionstb_ptr fcns = nullptr;
|
|
|
|
|
if(luaL_testudata(L, 2, formfcntbKey)) {
|
|
|
|
|
fcns = *static_cast<functionstb_ptr*>(lua_touserdata(L, 2));
|
|
|
|
|
} else if(lua_istable(L, 2)) {
|
|
|
|
|
// Create a functions table on the Lua stack
|
|
|
|
|
fcns = *new(L) functionstb_ptr(new function_symbol_table);
|
|
|
|
|
luaL_setmetatable(L, formfcntbKey);
|
|
|
|
|
// Set it to be collected
|
|
|
|
|
lua_owned_fcntb.insert(fcns);
|
|
|
|
|
// Iterate through the Lua table and register each entry as a function
|
|
|
|
|
int i_fcntb = lua_absindex(L, -1);
|
|
|
|
|
for(lua_pushnil(L); lua_next(L, i_fcntb - 1); lua_pop(L, 1)) {
|
|
|
|
|
// Just forward to the metafunction, which handles any error checking
|
|
|
|
|
lua_pushvalue(L, i_fcntb + 1); // The key (hopefully a valid string)
|
|
|
|
|
lua_pushvalue(L, i_fcntb + 2); // The value (hopefully a valid function)
|
|
|
|
|
lua_settable(L, i_fcntb); // Invokes the __newindex metafunction
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
new(L) fwrapper(lua_tostring(L, 1), fcns);
|
|
|
|
|
luaL_setmetatable(L, formulaKey);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
@ -283,6 +391,11 @@ lua_formula_bridge::fwrapper::fwrapper(const std::string& code, function_symbol_
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lua_formula_bridge::fwrapper::fwrapper(std::shared_ptr<formula_expression> expr)
|
|
|
|
|
: expr_ptr(expr)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string lua_formula_bridge::fwrapper::str() const
|
|
|
|
|
{
|
|
|
|
|
if(formula_ptr) {
|
|
|
|
@ -291,10 +404,30 @@ std::string lua_formula_bridge::fwrapper::str() const
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<formula> lua_formula_bridge::fwrapper::to_formula() const
|
|
|
|
|
{
|
|
|
|
|
if(formula_ptr) {
|
|
|
|
|
return formula_ptr;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<formula_expression> lua_formula_bridge::fwrapper::to_expr() const
|
|
|
|
|
{
|
|
|
|
|
if(formula_ptr) {
|
|
|
|
|
return formula_ptr->expr_;
|
|
|
|
|
} else if(expr_ptr) {
|
|
|
|
|
return expr_ptr;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
variant lua_formula_bridge::fwrapper::evaluate(const formula_callable& variables, formula_debugger* fdb) const
|
|
|
|
|
{
|
|
|
|
|
if(formula_ptr) {
|
|
|
|
|
return formula_ptr->evaluate(variables, fdb);
|
|
|
|
|
} else if(expr_ptr) {
|
|
|
|
|
return expr_ptr->evaluate(variables, fdb);
|
|
|
|
|
}
|
|
|
|
|
return variant();
|
|
|
|
|
}
|
|
|
|
@ -306,6 +439,27 @@ static int impl_formula_collect(lua_State* L)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int impl_formula_get(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
lua_formula_bridge::fwrapper* form = static_cast<lua_formula_bridge::fwrapper*>(lua_touserdata(L, 1));
|
|
|
|
|
std::string key = luaL_checkstring(L, 2);
|
|
|
|
|
if(key == "functions") {
|
|
|
|
|
if(std::shared_ptr<formula> f = form->to_formula()) {
|
|
|
|
|
// This should not happen, but just in case...
|
|
|
|
|
if(f->get_functions() == nullptr) return 0;
|
|
|
|
|
new(L) functionstb_ptr(f->get_functions());
|
|
|
|
|
luaL_setmetatable(L, formfcntbKey);
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
// The fwrapper is either invalid or wraps just a formula_expression, not a full formula.
|
|
|
|
|
// This form is only available from being passed to a function, I think.
|
|
|
|
|
lua_pushstring(L, "can't get functions table from argument formula");
|
|
|
|
|
return lua_error(L);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
@ -314,6 +468,164 @@ static int impl_formula_tostring(lua_State* L)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int impl_fcntb_collect(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
functionstb_ptr tb = *static_cast<functionstb_ptr*>(lua_touserdata(L, 1));
|
|
|
|
|
if(lua_owned_fcntb.count(tb)) {
|
|
|
|
|
lua_owned_fcntb.erase(tb);
|
|
|
|
|
tb->~function_symbol_table();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cfun_fcntb_call(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
functionstb_ptr tb = *static_cast<functionstb_ptr*>(lua_touserdata(L, lua_upvalueindex(1)));
|
|
|
|
|
std::string name = luaL_checkstring(L, lua_upvalueindex(2));
|
|
|
|
|
|
|
|
|
|
std::vector<expression_ptr> args;
|
|
|
|
|
for(int i = 1; i <= lua_gettop(L); i++) {
|
|
|
|
|
if(luaL_testudata(L, i, formulaKey)) {
|
|
|
|
|
lua_formula_bridge::fwrapper* form = static_cast<lua_formula_bridge::fwrapper*>(lua_touserdata(L, i));
|
|
|
|
|
args.push_back(form->to_expr());
|
|
|
|
|
} else {
|
|
|
|
|
variant v = luaW_tofaivariant(L, i);
|
|
|
|
|
std::string var;
|
|
|
|
|
if(!v.is_callable()) {
|
|
|
|
|
var = v.serialize_to_string();
|
|
|
|
|
} else if(auto lc = v.try_convert<lua_callable>()) {
|
|
|
|
|
std::vector<formula_input> inputs;
|
|
|
|
|
lc->get_inputs(inputs);
|
|
|
|
|
if(inputs.size() > 2) {
|
|
|
|
|
// Treat it as a map since it has string keys
|
|
|
|
|
variant vmap = lc->get_value("__map");
|
|
|
|
|
var = vmap.serialize_to_string();
|
|
|
|
|
} else {
|
|
|
|
|
// It could be a list or a map; check all keys
|
|
|
|
|
if(lc->is_list()) {
|
|
|
|
|
variant vlist = lc->get_value("__list");
|
|
|
|
|
var = vlist.serialize_to_string();
|
|
|
|
|
} else {
|
|
|
|
|
variant vmap = lc->get_value("__map");
|
|
|
|
|
var = vmap.serialize_to_string();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Just try to serialize it. It might actually work,
|
|
|
|
|
// or it might throw an error.
|
|
|
|
|
// (For example, location objects are serializable.)
|
|
|
|
|
var = v.serialize_to_string();
|
|
|
|
|
}
|
|
|
|
|
if(!var.empty()) {
|
|
|
|
|
// It's not an object, so push code for generating the value
|
|
|
|
|
lua_formula_bridge::fwrapper form(var, tb);
|
|
|
|
|
args.push_back(form.to_expr());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expression_ptr fcn = tb->create_function(name, args);
|
|
|
|
|
new(L) lua_formula_bridge::fwrapper(fcn);
|
|
|
|
|
luaL_setmetatable(L, formulaKey);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int impl_fcntb_get(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
if(!luaL_testudata(L, 1, formfcntbKey)) {
|
|
|
|
|
return luaW_type_error(L, 2, "formula function table");
|
|
|
|
|
}
|
|
|
|
|
if(!lua_isstring(L, 2)) {
|
|
|
|
|
return luaW_type_error(L, 2, lua_typename(L, lua_type(L, 2)));
|
|
|
|
|
}
|
|
|
|
|
// This closure simply consumes the two arguments to __index
|
|
|
|
|
lua_pushcclosure(L, cfun_fcntb_call, 2);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int impl_fcntb_set(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
functionstb_ptr tb = *static_cast<functionstb_ptr*>(lua_touserdata(L, 1));
|
|
|
|
|
std::string fcn_name = luaL_checkstring(L, 2);
|
|
|
|
|
if(lua_iscfunction(L, 3)) {
|
|
|
|
|
return luaL_argerror(L, 3, "expected Lua function, not C function");
|
|
|
|
|
} else if(!lua_isfunction(L, 3)) {
|
|
|
|
|
return luaW_type_error(L, 3, lua_typename(L, LUA_TFUNCTION));
|
|
|
|
|
}
|
|
|
|
|
if(formula::keywords.count(fcn_name)) {
|
|
|
|
|
return luaL_argerror(L, 2, "can't create a function whose name is a formula keyword");
|
|
|
|
|
}
|
|
|
|
|
// Make sure the function is at the top
|
|
|
|
|
// It probably is already, though
|
|
|
|
|
lua_settop(L, 3);
|
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
|
lua_Debug fcn_info;
|
|
|
|
|
lua_getinfo(L, ">u", &fcn_info);
|
|
|
|
|
if(fcn_info.nparams == 0) {
|
|
|
|
|
return luaL_argerror(L, 3, "expected Lua function taking at least one named argument");
|
|
|
|
|
}
|
|
|
|
|
int min_args = 1, max_args = fcn_info.isvararg ? -1 : fcn_info.nparams;
|
|
|
|
|
for(int i = 2; i <= fcn_info.nparams; i++) {
|
|
|
|
|
std::string var_name = lua_getlocal(L, nullptr, i);
|
|
|
|
|
if(var_name.find("_opt") != std::string::npos) {
|
|
|
|
|
min_args--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_kernel_base& kernel = lua_kernel_base::get_lua_kernel<lua_kernel_base>(L);
|
|
|
|
|
formula_function_ptr fcn(new lua_formula_function_defn(fcn_name, min_args - 1, max_args - 1, kernel));
|
|
|
|
|
lua_pushvalue(L, 3);
|
|
|
|
|
if(fcn_info.nups > 0) {
|
|
|
|
|
// Replace _ENV with a minimal environment containing only pure functions
|
|
|
|
|
static const char*const globals[] = {
|
|
|
|
|
// Basic iteration functions
|
|
|
|
|
"pairs", "ipairs", "next",
|
|
|
|
|
// Basic information functions
|
|
|
|
|
"type", "select", "rawget", "rawlen", "rawequal", "_VERSION",
|
|
|
|
|
// Conversions
|
|
|
|
|
"tostring", "tonumber",
|
|
|
|
|
// Pure modules
|
|
|
|
|
"math", "mathx", "string", "stringx", "utf8",
|
|
|
|
|
};
|
|
|
|
|
static const char*const wesnoth[] = {
|
|
|
|
|
// Version info
|
|
|
|
|
"current_version", "version",
|
|
|
|
|
// Misc functions
|
|
|
|
|
"ms_since_init", "named_tuple", "textdomain",
|
|
|
|
|
// Global data
|
|
|
|
|
"colors", "game_config", "get_language",
|
|
|
|
|
};
|
|
|
|
|
static const char*const wml[] = {
|
|
|
|
|
"attribute_count", "child_array", "child_count", "child_range", "find_child",
|
|
|
|
|
"get_child", "get_nth_child", "tag", "clone", "equal", "valid", "matches_filter",
|
|
|
|
|
"parse", "merge", "diff", "patch", "interpolate", "tostring"
|
|
|
|
|
};
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
for(auto glob : globals) {
|
|
|
|
|
lua_getglobal(L, glob);
|
|
|
|
|
lua_setfield(L, -2, glob);
|
|
|
|
|
}
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
for(auto wes : wesnoth) {
|
|
|
|
|
luaW_getglobal(L, "wesnoth", wes);
|
|
|
|
|
lua_setfield(L, -2, wes);
|
|
|
|
|
}
|
|
|
|
|
lua_setfield(L, -2, "wesnoth");
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
for(auto w : wml) {
|
|
|
|
|
luaW_getglobal(L, "wml", w);
|
|
|
|
|
lua_setfield(L, -2, w);
|
|
|
|
|
}
|
|
|
|
|
lua_setfield(L, -2, "wml");
|
|
|
|
|
// Also add the function table itself as a global
|
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
|
lua_setfield(L, -2, "wfl_functions");
|
|
|
|
|
lua_setupvalue(L, -2, 1);
|
|
|
|
|
}
|
|
|
|
|
lua_rawsetp(L, LUA_REGISTRYINDEX, fcn.get());
|
|
|
|
|
tb->add_function(fcn_name, std::move(fcn));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string lua_formula_bridge::register_metatables(lua_State* L)
|
|
|
|
|
{
|
|
|
|
|
luaL_newmetatable(L, formulaKey);
|
|
|
|
@ -323,8 +635,20 @@ std::string lua_formula_bridge::register_metatables(lua_State* L)
|
|
|
|
|
lua_setfield(L, -2, "__tostring");
|
|
|
|
|
lua_pushcfunction(L, intf_eval_formula);
|
|
|
|
|
lua_setfield(L, -2, "__call");
|
|
|
|
|
lua_pushcfunction(L, impl_formula_get);
|
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
|
lua_pushstring(L, "formula");
|
|
|
|
|
lua_setfield(L, -2, "__metatable");
|
|
|
|
|
|
|
|
|
|
return "Adding formula metatable...\n";
|
|
|
|
|
luaL_newmetatable(L, formfcntbKey);
|
|
|
|
|
lua_pushcfunction(L, impl_fcntb_collect);
|
|
|
|
|
lua_setfield(L, -2, "__gc");
|
|
|
|
|
lua_pushcfunction(L, impl_fcntb_get);
|
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
|
lua_pushcfunction(L, impl_fcntb_set);
|
|
|
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
|
lua_pushstring(L, "formula functions");
|
|
|
|
|
lua_setfield(L, -2, "__metatable");
|
|
|
|
|
|
|
|
|
|
return "Adding formula metatable...\nAdding formula function table metatable";
|
|
|
|
|
}
|
|
|
|
|