1 /*
2 * Copyright (C) 2006-2020 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 /*
21 * This code was inspired from the lua_users wiki:
22 * http://lua-users.org/wiki/SimplerCppBinding
23 * and by some code written by TheBunny:
24 * http://plaidworld.com/
25 *
26 * A lot of new features (e.g. inheritance) were added for Widelands.
27 */
28
29 #ifndef WL_SCRIPTING_LUNA_H
30 #define WL_SCRIPTING_LUNA_H
31
32 #define LUNA_CLASS_HEAD(klass) \
33 static const char className[]; \
34 static const MethodType<klass> Methods[]; \
35 static const PropertyType<klass> Properties[]
36
37 /*
38 * Macros for filling the description tables
39 */
40 #define PROP_RO(klass, name) \
41 { #name, &klass::get_##name, 0 }
42 #define PROP_RW(klass, name) \
43 { #name, &klass::get_##name, &klass::set_##name }
44 #define METHOD(klass, name) \
45 { #name, &klass::name }
46
47 /*
48 * Macros for helping with persistence and unpersistence
49 */
50 #define PERS_TYPE(name, value, type) \
51 lua_push##type(L, value); \
52 lua_setfield(L, -2, name)
53 #define PERS_INT32(name, value) PERS_TYPE(name, value, int32)
54 #define PERS_UINT32(name, value) PERS_TYPE(name, value, uint32)
55 #define PERS_STRING(name, value) PERS_TYPE(name, value.c_str(), string)
56
57 #define UNPERS_TYPE(name, value, type) \
58 lua_getfield(L, lua_upvalueindex(1), name); \
59 value = luaL_check##type(L, -1); \
60 lua_pop(L, 1);
61 #define UNPERS_INT32(name, value) UNPERS_TYPE(name, value, int32)
62 #define UNPERS_UINT32(name, value) UNPERS_TYPE(name, value, uint32)
63 #define UNPERS_STRING(name, value) UNPERS_TYPE(name, value, string)
64
65 #include <cstring>
66
67 #include "scripting/lua.h"
68 #include "scripting/luna_impl.h"
69
70 /**
71 * Base Class. All Luna class must derive from this
72 */
73 class LunaClass {
74 public:
~LunaClass()75 virtual ~LunaClass() {
76 }
77 virtual void __persist(lua_State*) = 0;
78 virtual void __unpersist(lua_State*) = 0;
79 virtual const char* get_modulename() = 0;
80 };
81
82 /**
83 * Register the class as a Lua class (that is a metatable and a function to
84 * create an object out of this table).
85 *
86 * The class will always be created in the namespace wl, sub_namespace can
87 * be used to create the class in one depth deeper (e.g. wl.map)
88 */
89 template <class T>
90 void register_class(lua_State* const L,
91 char const* const sub_namespace = "",
92 bool return_metatable = false) {
93 int to_pop = 0;
94
95 // Get wl table which MUST already exist
96 lua_getglobal(L, "wl");
97 to_pop++;
98
99 // push the wl sub namespace table onto the stack, if desired
100 if (strlen(sub_namespace) != 0) {
101 lua_getfield(L, -1, sub_namespace);
102 to_pop++;
103 }
104
105 add_constructor_to_lua<T>(L);
106 add_instantiator_to_lua<T>(L);
107 lua_pop(L, to_pop); // Pop everything we used so far.
108
109 create_metatable_for_class<T>(L);
110
111 register_properties_in_metatable<T, T>(L);
112 register_methods_in_metatable<T, T>(L);
113
114 if (!return_metatable)
115 lua_pop(L, 1); // remove the Metatable
116 }
117 /**
118 * Makes the first class a children of the second. Make sure that T is really a
119 * child class of PT before calling this. This must also be called directly
120 * after register_class, so that the Metatable index is still valid
121 */
add_parent(lua_State * L)122 template <class T, class PT> void add_parent(lua_State* L) {
123 register_properties_in_metatable<T, PT>(L);
124 register_methods_in_metatable<T, PT>(L);
125 }
126
127 /*
128 * Get the instance of this C object to lua. This is usually used
129 * as last call in a function that should create a new Lua object
130 */
to_lua(lua_State * const L,T * const obj)131 template <class T> int to_lua(lua_State* const L, T* const obj) {
132 // Create a new table with some slots preallocated
133 lua_createtable(L, 0, 30); // table
134
135 // get the index of the new table on the stack
136 int const newtable = lua_gettop(L);
137
138 // push index of position of user data in our array
139 lua_pushnumber(L, 0); // table 0
140
141 // Make a new userdata. A lightuserdata won't do since we want to assign
142 // a metatable to it
143 T** const a = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
144 *a = obj;
145
146 int const userdata = lua_gettop(L); // table 0 ud
147
148 // Assign this metatable to this userdata. We only do this to add
149 // garbage collection to this userdata, so that the destructor gets
150 // called. As a (unwanted, but not critical) side effect we also add all
151 // other methods to this object
152 luaL_getmetatable(L, T::className); // table 0 ud mt
153 lua_setmetatable(L, userdata); // table 0 ud
154
155 // table[ 0 ] = USERDATA;
156 lua_settable(L, newtable); // table
157
158 // Assign this metatable to the newly created table
159 luaL_getmetatable(L, T::className);
160 lua_setmetatable(L, newtable);
161
162 // table
163 return 1;
164 }
165
166 /*
167 * Our userdata is saved in table[0]. This function fetches it and makes sure
168 * that it is the correct userdata.
169 */
get_user_class(lua_State * const L,int narg)170 template <class T> T** get_user_class(lua_State* const L, int narg) {
171 extract_userdata_from_user_class<T>(L, narg);
172
173 T** rv = static_cast<T**>(luaL_checkudata(L, -1, T::className));
174 lua_pop(L, 1);
175
176 return rv;
177 }
178 /*
179 * This forces the pointer to be a base class. ONLY use this if you are sure
180 * that indeed the object is a base class, like you can be in __eq
181 */
get_base_user_class(lua_State * const L,int narg)182 template <class T> T** get_base_user_class(lua_State* const L, int narg) {
183 extract_userdata_from_user_class<T>(L, narg);
184
185 T** rv = static_cast<T**>(lua_touserdata(L, -1));
186 lua_pop(L, 1);
187
188 return rv;
189 }
190
191 #endif // end of include guard: WL_SCRIPTING_LUNA_H
192