The Battle for Wesnoth  1.17.0-dev
lua_cpp_function.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2021
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "log.hpp"
19 
20 #include <sstream>
21 #include <string>
22 
23 #include "lua/lauxlib.h"
24 #include "lua/lua.h"
25 #include "scripting/lua_common.hpp" // for new(L)
26 
27 static lg::log_domain log_scripting_lua("scripting/lua");
28 #define DBG_LUA LOG_STREAM(debug, log_scripting_lua)
29 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
30 #define WRN_LUA LOG_STREAM(warn, log_scripting_lua)
31 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
32 
33 namespace lua_cpp {
34 
35 char const * cpp_function = "CPP_Function";
36 
37 static int intf_dispatcher ( lua_State* L )
38 {
39  //make a temporary copy, in case lua_remove(L,1) might cause lua to garbage collect and destroy it
40  lua_function f = * static_cast<lua_function *> (luaL_checkudata(L, 1, cpp_function));
41  // remove from the stack before executing, so that like all other callbacks, f finds only its intended arguments on the stack.
42  lua_remove(L,1);
43  int result = (f)(L);
44  return result;
45 }
46 
47 static int intf_cleanup ( lua_State* L )
48 {
49  lua_function * d = static_cast< lua_function *> (luaL_testudata(L, 1, cpp_function));
50  if (d == nullptr) {
51  ERR_LUA << "lua_cpp::intf_cleanup called on data of type: " << lua_typename( L, lua_type( L, 1 ) ) << std::endl;
52  ERR_LUA << "This may indicate a memory leak, please report at bugs.wesnoth.org" << std::endl;
53  lua_pushstring(L, "C++ function object garbage collection failure");
54  lua_error(L);
55  } else {
56  d->~lua_function();
57  }
58  return 0;
59 }
60 
61 static int intf_tostring( lua_State* L )
62 {
63  lua_function * d = static_cast< lua_function *> (luaL_checkudata(L, 1, cpp_function));
64  // d is not null, if it was null then checkudata raised a lua error and a longjump was executed.
65  std::stringstream result;
66  result << "c++ function: " << std::hex << d;
67  lua_pushstring(L, result.str().c_str());
68  return 1;
69 }
70 
72 {
73  luaL_newmetatable(L, cpp_function);
75  lua_setfield(L, -2, "__call");
77  lua_setfield(L, -2, "__gc");
79  lua_setfield(L, -2, "__tostring");
80  lua_pushstring(L, "function");
81  lua_setfield(L, -2, "__metatable");
82  lua_pushvalue(L, -1); //make a copy of this table, set it to be its own __index table
83  lua_setfield(L, -2, "__index");
84 
85  lua_pop(L, 1);
86 }
87 
89 {
90  new(L) lua_function(f);
91  luaL_setmetatable(L, cpp_function);
92 }
93 
94 void set_functions( lua_State* L, const std::vector<lua_cpp::Reg>& functions)
95 {
97  for (const lua_cpp::Reg& l : functions) { /* fill the table with given functions */
98  if (l.name != nullptr) {
99  push_function(L, l.func);
100  lua_setfield(L, -2, l.name);
101  }
102  }
103 }
104 
106 {
107  lua_function * f = static_cast< lua_function *> (luaL_checkudata(L, lua_upvalueindex(1), cpp_function)); //assume the std::function is the first upvalue
108  return (*f)(L);
109 }
110 
111 void push_closure( lua_State* L, const lua_function & f, int nup)
112 {
113  push_function(L, f);
114  lua_insert(L, -(1+nup)); //move the function beneath the upvalues
116 }
117 
118 void set_functions( lua_State* L, const std::vector<lua_cpp::Reg>& functions, int nup )
119 {
121  luaL_checkstack(L, nup+1, "too many upvalues");
122  for (const lua_cpp::Reg& l : functions) { /* fill the table with given functions */
123  if (l.name == nullptr) {
124  continue;
125  }
126  int i;
127  for (i = 0; i < nup; ++i) /* copy upvalues to the top */
128  lua_pushvalue(L, -nup);
129  push_closure(L, l.func, nup); /* closure with those upvalues */
130  lua_setfield(L, -(nup + 2), l.name);
131  }
132  lua_pop(L, nup); /* remove upvalues */
133 }
134 
135 } // end namespace lua_cpp
std::function< int(lua_State *)> lua_function
LUALIB_API void * luaL_checkudata(lua_State *L, int ud, const char *tname)
Definition: lauxlib.cpp:345
#define lua_pushcfunction(L, f)
Definition: lua.h:370
LUA_API int lua_type(lua_State *L, int idx)
Definition: lapi.cpp:260
#define ERR_LUA
static int intf_closure_dispatcher(lua_State *L)
#define lua_remove(L, idx)
Definition: lua.h:391
LUALIB_API void luaL_checkstack(lua_State *L, int space, const char *msg)
Definition: lauxlib.cpp:380
LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n)
Definition: lapi.cpp:555
#define d
LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:324
void push_function(lua_State *L, const lua_function &f)
Pushes a std::function wrapper object onto the stack.
#define lua_pop(L, n)
Definition: lua.h:364
#define lua_upvalueindex(i)
Definition: lua.h:45
static int intf_cleanup(lua_State *L)
void push_closure(lua_State *L, const lua_function &f, int nup)
Pushes a closure which retains a std::function object as its first up-value.
LUALIB_API void * luaL_testudata(lua_State *L, int ud, const char *tname)
Definition: lauxlib.cpp:330
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:311
#define luaL_checkversion(L)
Definition: lauxlib.h:46
std::size_t i
Definition: function.cpp:967
char const * cpp_function
static int intf_dispatcher(lua_State *L)
LUA_API void lua_pushvalue(lua_State *L, int idx)
Definition: lapi.cpp:246
LUA_API int lua_error(lua_State *L)
Definition: lapi.cpp:1205
#define f
#define lua_insert(L, idx)
Definition: lua.h:389
Standard logging facilities (interface).
void register_metatable(lua_State *L)
static int intf_tostring(lua_State *L)
static lg::log_domain log_scripting_lua("scripting/lua")
LUA_API const char * lua_pushstring(lua_State *L, const char *s)
Definition: lapi.cpp:514
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
Definition: lapi.cpp:837
LUA_API const char * lua_typename(lua_State *L, int t)
Definition: lapi.cpp:266
void set_functions(lua_State *L, const std::vector< lua_cpp::Reg > &functions)
Analogous to lua_setfuncs, it registers a collection of function wrapper objects into a table...