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