The Battle for Wesnoth  1.15.0-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 http://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_pushvalue(L, -1); //make a copy of this table, set it to be its own __index table
80  lua_setfield(L, -2, "__index");
81 
82  lua_pop(L, 1);
83 }
84 
86 {
87  new(L) lua_function(f);
88  luaL_setmetatable(L, cpp_function);
89 }
90 
91 void set_functions( lua_State* L, const std::vector<lua_cpp::Reg>& functions)
92 {
94  for (const lua_cpp::Reg& l : functions) { /* fill the table with given functions */
95  if (l.name != nullptr) {
96  push_function(L, l.func);
97  lua_setfield(L, -2, l.name);
98  }
99  }
100 }
101 
103 {
104  lua_function * f = static_cast< lua_function *> (luaL_checkudata(L, lua_upvalueindex(1), cpp_function)); //assume the std::function is the first upvalue
105  return (*f)(L);
106 }
107 
108 void push_closure( lua_State* L, const lua_function & f, int nup)
109 {
110  push_function(L, f);
111  lua_insert(L, -(1+nup)); //move the function beneath the upvalues
113 }
114 
115 void set_functions( lua_State* L, const std::vector<lua_cpp::Reg>& functions, int nup )
116 {
118  luaL_checkstack(L, nup+1, "too many upvalues");
119  for (const lua_cpp::Reg& l : functions) { /* fill the table with given functions */
120  if (l.name == nullptr) {
121  continue;
122  }
123  int i;
124  for (i = 0; i < nup; ++i) /* copy upvalues to the top */
125  lua_pushvalue(L, -nup);
126  push_closure(L, l.func, nup); /* closure with those upvalues */
127  lua_setfield(L, -(nup + 2), l.name);
128  }
129  lua_pop(L, nup); /* remove upvalues */
130 }
131 
132 } // 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:333
#define lua_pushcfunction(L, f)
Definition: lua.h:350
LUA_API int lua_type(lua_State *L, int idx)
Definition: lapi.cpp:251
#define ERR_LUA
static int intf_closure_dispatcher(lua_State *L)
#define lua_remove(L, idx)
Definition: lua.h:371
LUALIB_API void luaL_checkstack(lua_State *L, int space, const char *msg)
Definition: lauxlib.cpp:368
LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n)
Definition: lapi.cpp:532
#define d
LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:312
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:344
#define lua_upvalueindex(i)
Definition: lua.h:43
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:318
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:299
#define luaL_checkversion(L)
Definition: lauxlib.h:40
std::size_t i
Definition: function.cpp:933
char const * cpp_function
static int intf_dispatcher(lua_State *L)
LUA_API void lua_pushvalue(lua_State *L, int idx)
Definition: lapi.cpp:237
LUA_API int lua_error(lua_State *L)
Definition: lapi.cpp:1113
#define f
#define lua_insert(L, idx)
Definition: lua.h:369
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:491
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
Definition: lapi.cpp:776
LUA_API const char * lua_typename(lua_State *L, int t)
Definition: lapi.cpp:257
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...