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