New inheritance graph code.
[luabind.git] / src / class_rep.cpp
blob6fc6401e215e4a64452175d530ab42a44a119a65
1 // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
23 #define LUABIND_BUILDING
25 #include <luabind/lua_include.hpp>
27 #include <luabind/detail/stack_utils.hpp>
28 #include <luabind/detail/conversion_storage.hpp>
29 #include <luabind/luabind.hpp>
30 #include <luabind/exception_handler.hpp>
31 #include <utility>
33 using namespace luabind::detail;
35 namespace luabind { namespace detail
37 LUABIND_API int property_tag(lua_State* L)
39 lua_pushstring(L, "luabind: property_tag function can't be called");
40 lua_error(L);
41 return 0;
45 luabind::detail::class_rep::class_rep(type_id const& type
46 , const char* name
47 , lua_State* L
49 : m_type(type)
50 , m_name(name)
51 , m_class_type(cpp_class)
52 , m_operator_cache(0)
54 lua_newtable(L);
55 handle(L, -1).swap(m_table);
56 lua_newtable(L);
57 handle(L, -1).swap(m_default_table);
58 lua_pop(L, 2);
60 class_registry* r = class_registry::get_registry(L);
61 assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()");
63 lua_rawgeti(L, LUA_REGISTRYINDEX, r->cpp_class());
64 lua_setmetatable(L, -2);
66 lua_pushvalue(L, -1); // duplicate our user data
67 m_self_ref.set(L);
69 m_instance_metatable = r->cpp_instance();
71 lua_pushstring(L, "__luabind_cast_graph");
72 lua_gettable(L, LUA_REGISTRYINDEX);
73 m_casts = static_cast<cast_graph*>(lua_touserdata(L, -1));
74 lua_pop(L, 1);
76 lua_pushstring(L, "__luabind_class_id_map");
77 lua_gettable(L, LUA_REGISTRYINDEX);
78 m_classes = static_cast<class_id_map*>(lua_touserdata(L, -1));
79 lua_pop(L, 1);
82 luabind::detail::class_rep::class_rep(lua_State* L, const char* name)
83 : m_type(typeid(null_type))
84 , m_name(name)
85 , m_class_type(lua_class)
86 , m_operator_cache(0)
88 lua_newtable(L);
89 handle(L, -1).swap(m_table);
90 lua_newtable(L);
91 handle(L, -1).swap(m_default_table);
92 lua_pop(L, 2);
94 class_registry* r = class_registry::get_registry(L);
95 assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()");
97 lua_rawgeti(L, LUA_REGISTRYINDEX, r->lua_class());
98 lua_setmetatable(L, -2);
99 lua_pushvalue(L, -1); // duplicate our user data
100 m_self_ref.set(L);
102 m_instance_metatable = r->lua_instance();
104 lua_pushstring(L, "__luabind_cast_graph");
105 lua_gettable(L, LUA_REGISTRYINDEX);
106 m_casts = static_cast<cast_graph*>(lua_touserdata(L, -1));
107 lua_pop(L, 1);
109 lua_pushstring(L, "__luabind_class_id_map");
110 lua_gettable(L, LUA_REGISTRYINDEX);
111 m_classes = static_cast<class_id_map*>(lua_touserdata(L, -1));
112 lua_pop(L, 1);
115 luabind::detail::class_rep::~class_rep()
119 // leaves object on lua stack
120 std::pair<void*,void*>
121 luabind::detail::class_rep::allocate(lua_State* L) const
123 const int size = sizeof(object_rep);
124 char* mem = static_cast<char*>(lua_newuserdata(L, size));
125 return std::pair<void*,void*>(mem, 0);
129 // this is called as metamethod __call on the class_rep.
130 int luabind::detail::class_rep::constructor_dispatcher(lua_State* L)
132 class_rep* cls = static_cast<class_rep*>(lua_touserdata(L, 1));
134 int args = lua_gettop(L);
136 push_new_instance(L, cls);
138 cls->get_table(L);
139 lua_setfenv(L, -2);
141 lua_rawgeti(L, LUA_REGISTRYINDEX, cls->metatable_ref());
142 lua_setmetatable(L, -2);
144 if (cls->get_class_type() == class_rep::lua_class
145 && !cls->bases().empty())
147 lua_pushstring(L, "super");
148 lua_pushvalue(L, 1);
149 lua_pushvalue(L, -3);
150 lua_pushcclosure(L, super_callback, 2);
151 lua_settable(L, LUA_GLOBALSINDEX);
154 lua_pushvalue(L, -1);
155 lua_replace(L, 1);
157 cls->get_table(L);
158 lua_pushstring(L, "__init");
159 lua_gettable(L, -2);
161 lua_insert(L, 1);
163 lua_pop(L, 1);
164 lua_insert(L, 1);
166 lua_call(L, args, 0);
168 return 1;
171 void luabind::detail::class_rep::add_base_class(const luabind::detail::class_rep::base_info& binfo)
173 // If you hit this assert you are deriving from a type that is not registered
174 // in lua. That is, in the class_<> you are giving a baseclass that isn't registered.
175 // Please note that if you don't need to have access to the base class or the
176 // conversion from the derived class to the base class, you don't need
177 // to tell luabind that it derives.
178 assert(binfo.base && "You cannot derive from an unregistered type");
180 class_rep* bcrep = binfo.base;
182 // import all static constants
183 for (std::map<const char*, int, ltstr>::const_iterator i = bcrep->m_static_constants.begin();
184 i != bcrep->m_static_constants.end(); ++i)
186 int& v = m_static_constants[i->first];
187 v = i->second;
190 // also, save the baseclass info to be used for typecasts
191 m_bases.push_back(binfo);
194 namespace
197 bool super_deprecation_disabled = false;
199 } // namespace unnamed
201 LUABIND_API void luabind::disable_super_deprecation()
203 super_deprecation_disabled = true;
206 int luabind::detail::class_rep::super_callback(lua_State* L)
208 if (!super_deprecation_disabled)
210 lua_pushstring(L,
211 "DEPRECATION: 'super' has been deprecated in favor of "
212 "directly calling the base class __init() function. "
213 "This error can be disabled by calling 'luabind::disable_super_deprecation()'."
215 lua_error(L);
218 int args = lua_gettop(L);
220 class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, lua_upvalueindex(1)));
221 class_rep* base = crep->bases()[0].base;
223 if (base->bases().empty())
225 lua_pushstring(L, "super");
226 lua_pushnil(L);
227 lua_settable(L, LUA_GLOBALSINDEX);
229 else
231 lua_pushstring(L, "super");
232 lua_pushlightuserdata(L, base);
233 lua_pushvalue(L, lua_upvalueindex(2));
234 lua_pushcclosure(L, super_callback, 2);
235 lua_settable(L, LUA_GLOBALSINDEX);
238 base->get_table(L);
239 lua_pushstring(L, "__init");
240 lua_gettable(L, -2);
241 lua_insert(L, 1);
242 lua_pop(L, 1);
244 lua_pushvalue(L, lua_upvalueindex(2));
245 lua_insert(L, 2);
247 lua_call(L, args + 1, 0);
249 // TODO: instead of clearing the global variable "super"
250 // store it temporarily in the registry. maybe we should
251 // have some kind of warning if the super global is used?
252 lua_pushstring(L, "super");
253 lua_pushnil(L);
254 lua_settable(L, LUA_GLOBALSINDEX);
256 return 0;
261 int luabind::detail::class_rep::lua_settable_dispatcher(lua_State* L)
263 class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
265 // get first table
266 crep->get_table(L);
268 // copy key, value
269 lua_pushvalue(L, -3);
270 lua_pushvalue(L, -3);
271 lua_rawset(L, -3);
272 // pop table
273 lua_pop(L, 1);
275 // get default table
276 crep->get_default_table(L);
277 lua_replace(L, 1);
278 lua_rawset(L, -3);
280 crep->m_operator_cache = 0; // invalidate cache
282 return 0;
286 stack:
287 1: class_rep
288 2: member name
290 int luabind::detail::class_rep::static_class_gettable(lua_State* L)
292 class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
294 // look in the static function table
295 crep->get_default_table(L);
296 lua_pushvalue(L, 2);
297 lua_gettable(L, -2);
298 if (!lua_isnil(L, -1)) return 1;
299 else lua_pop(L, 2);
301 const char* key = lua_tostring(L, 2);
303 if (std::strlen(key) != lua_strlen(L, 2))
305 lua_pushnil(L);
306 return 1;
309 std::map<const char*, int, ltstr>::const_iterator j = crep->m_static_constants.find(key);
311 if (j != crep->m_static_constants.end())
313 lua_pushnumber(L, j->second);
314 return 1;
317 #ifndef LUABIND_NO_ERROR_CHECKING
320 std::string msg = "no static '";
321 msg += key;
322 msg += "' in class '";
323 msg += crep->name();
324 msg += "'";
325 lua_pushstring(L, msg.c_str());
327 lua_error(L);
329 #endif
331 lua_pushnil(L);
333 return 1;
336 bool luabind::detail::is_class_rep(lua_State* L, int index)
338 if (lua_getmetatable(L, index) == 0) return false;
340 lua_pushstring(L, "__luabind_classrep");
341 lua_gettable(L, -2);
342 if (lua_toboolean(L, -1))
344 lua_pop(L, 2);
345 return true;
348 lua_pop(L, 2);
349 return false;
352 void luabind::detail::finalize(lua_State* L, class_rep* crep)
354 if (crep->get_class_type() != class_rep::lua_class) return;
356 // lua_pushvalue(L, -1); // copy the object ref
357 crep->get_table(L);
358 lua_pushstring(L, "__finalize");
359 lua_gettable(L, -2);
360 lua_remove(L, -2);
362 if (lua_isnil(L, -1))
364 lua_pop(L, 1);
366 else
368 lua_pushvalue(L, -2);
369 lua_call(L, 1, 0);
372 for (std::vector<class_rep::base_info>::const_iterator
373 i = crep->bases().begin(); i != crep->bases().end(); ++i)
375 if (i->base) finalize(L, i->base);
379 void luabind::detail::class_rep::cache_operators(lua_State* L)
381 m_operator_cache = 0x1;
383 for (int i = 0; i < number_of_operators; ++i)
385 get_table(L);
386 lua_pushstring(L, get_operator_name(i));
387 lua_rawget(L, -2);
389 if (lua_isfunction(L, -1)) m_operator_cache |= 1 << (i + 1);
391 lua_pop(L, 2);
395 bool luabind::detail::class_rep::has_operator_in_lua(lua_State* L, int id)
397 if ((m_operator_cache & 0x1) == 0)
398 cache_operators(L);
400 const int mask = 1 << (id + 1);
402 return (m_operator_cache & mask) != 0;