some support for binding namespaces instead of classes
[lqt.git] / lqt_common.cpp
blob30547643c93a22b3f96e76e849cc4d0134f12c41
1 #include "lqt_common.hpp"
3 #define LQT_FIXEDINDEX(i) (i<0?(1+lua_gettop(L)+i):i)
5 //#include <QDebug>
6 #ifndef SEE_STACK
7 # define SEE_STACK(L, j) for (int j=1;j<=lua_gettop(L);j++) { qDebug() << j << '=' << luaL_typename(L, j) << '@' << lua_topointer (L, j); }
8 #endif
10 // TODO
12 // - add a metatable for void* which always results in nil and possibly
13 // accounts for reassigning the userdata to the right metatable.
14 // - proper descending down the dependency tree for indexing, and proper
15 // handling of missing binds
19 //#include <iostream>
20 //using namespace std;
22 void lqtL_setvoidmetatable (lua_State *L, int i, const char *t = 0) {
23 i = LQT_FIXEDINDEX(i);
24 if (luaL_newmetatable(L, "void*")) {
25 lua_newtable(L);
26 lua_setfield(L, -2, "__index");
27 lua_pushstring(L, "void*");
28 lua_setfield(L, -2, "__qtype");
30 lua_setmetatable(L, i);
31 if (t!=0) {
32 lua_newtable(L);
33 lua_pushstring(L, t);
34 lua_setfield(L, -2, "__unknown_type");
35 lua_setfenv(L, i);
39 void lqtL_getpointers (lua_State *L) {
40 lua_getfield(L, LUA_REGISTRYINDEX, LQT_POINTERS);
41 if (!lua_istable(L, -1)) {
42 //cout << "Registry Pointers created" << endl;
43 lua_pop(L, 1);
44 lua_newtable(L);
45 lua_newtable(L);
46 lua_pushstring(L, "kv");
47 lua_setfield(L, -2, "__mode");
48 lua_setmetatable(L, -2);
49 lua_pushvalue(L, -1);
50 lua_setfield(L, LUA_REGISTRYINDEX, LQT_POINTERS);
52 return;
55 int lqtL_reusepointer (lua_State *L, const void *p, const char *t) {
56 lqtL_getpointers(L);
57 lua_pushlightuserdata(L, const_cast<void*>(p));
58 lua_gettable(L, -2);
59 if (lqtL_testudata(L, -1, t) && (p==*(const void**)lua_touserdata(L, -1))) {
60 lua_remove(L, -2);
61 //qDebug();
62 //qDebug() << "reused" << p << "in" << lua_touserdata(L, -1) << t;
63 //lua_getmetatable(L, -1);luaL_getmetatable(L, t);
64 //qDebug() << "meta" << lua_topointer(L, -2) << "type" << lua_topointer(L, -1);
65 //lua_pop(L, 2);
66 return 1;
68 lua_pop(L, 2);
69 return 0;
72 void lqtL_pushpointer (lua_State *L, const void *obj, const char *t) {
73 const void **objp = (const void**)lua_newuserdata(L, sizeof(const void *));
74 *objp = 0;
75 lua_getfield(L, LUA_REGISTRYINDEX, t);
76 if (lua_istable(L, -1)) {
77 lua_setmetatable(L, -2);
78 lua_newtable(L);
79 lua_setfenv(L, -2);
80 } else {
81 //cout << "NO metatable given" << endl;
82 // TODO: add a fallback?
83 lua_pop(L, 1);
84 lqtL_setvoidmetatable(L, -1, t);
86 *objp = obj;
87 //cout << "pushed " << objp << ' ' << obj << endl;
90 void lqtL_setpointer (lua_State *L, int i, const void *obj) {
91 int index = i<0?(1+lua_gettop(L)+i):i;
92 //cout << lua_gettop(L) << ' ' << i << ' ' << index << endl;
93 lqtL_getpointers(L);
94 lua_pushlightuserdata(L, const_cast<void *>(obj));
95 lua_pushvalue(L, index);
96 lua_settable(L, -3);
97 lua_pop(L, 1);
98 return;
100 void lqtL_unsetpointer (lua_State *L, const void *obj) {
101 lqtL_getpointers(L);
102 lua_pushlightuserdata(L, const_cast<void *>(obj));
103 lua_pushnil(L);
104 lua_settable(L, -3);
105 lua_pop(L, 1);
106 return;
109 // TODO: don't need, it's debug
110 void * lqtL_topointer (lua_State *L, int i) {
111 void * ret = NULL;
112 ret = lua_touserdata(L, i);
113 ret = (ret==0)?0:*static_cast<void**>(ret);
114 return ret;
117 void lqtL_unmanageudata (lua_State *L, int i) {
118 if (!lua_isuserdata(L, i)) return;
119 lua_getfenv(L, i);
120 if (lua_istable(L, -1)) {
121 lua_pushnil(L);
122 lua_setfield(L, -2, "__gc");
124 lua_pop(L, 1);
125 return;
127 void lqtL_manageudata (lua_State *L, int index) {
128 //luaL_checkstack(L, 20, "");
129 index = LQT_FIXEDINDEX(index);
130 if (!lua_isuserdata(L, index)) return;
131 lua_getfield(L, index, "delete");
132 if (!lua_isfunction(L, -1)) {
133 lua_pop(L, 1);
134 return;
136 lua_getfenv(L, index);
137 if (!lua_istable(L, -1)) {
138 lua_pop(L, 1);
139 //if (1) {
140 lua_newtable(L);
141 lua_pushvalue(L, -1);
142 lua_setfenv(L, index);
144 lua_insert(L, -2);
145 lua_setfield(L, -2, "__gc");
146 lua_pop(L, 1);
147 return;
149 void lqtL_pushudata (lua_State *L, const void *obj, const char *t) {
150 // TODO: make the udata unique
151 //cout << endl << "pushing udata " << obj << " with type " << t << endl;
153 lua_checkstack(L, 5);
154 if (1) {
155 if (lqtL_reusepointer(L, obj, t)) {
156 //cout << obj << " reused " << t << endl;
157 return;
159 //cout << obj << " NOT reused " << t << endl;
160 } else {
161 lqtL_getpointers(L);
162 lua_pushlightuserdata(L, const_cast<void *>(obj));
163 lua_gettable(L, -2);
164 if (0) {
165 //cout << lua_gettop(L) << endl;
166 lua_getglobal(L, "print");
167 if (lua_getmetatable(L, -2)) {
168 //cout << "metatable "; // << lua_tostring(L, -1) << endl << endl;
169 lua_call(L, 1, 0);
170 } else {
171 //cout << "no metatable" << endl;
172 lua_pop(L, 1);
174 //cout << lua_gettop(L) << endl;
175 lua_getglobal(L, "print");
176 lua_getfield(L, LUA_REGISTRYINDEX, t);
177 //cout << "registry "; // << lua_tostring(L, -1) << endl; lua_pop(L, 1);
178 lua_call(L, 1, 0);
179 } else if (0) {
180 //cout << lua_gettop(L) << endl;
181 if (lua_getmetatable(L, -1)) {
182 lua_getfield(L, LUA_REGISTRYINDEX, t);
183 //cout << (bool)lua_equal(L, -1, -2) << endl;
184 lua_getglobal(L, "print");
185 lua_insert(L, -3);
186 lua_call(L, 2, 0);
187 } else {
188 //cout << "no metatable" << endl;
189 lua_pop(L, 1);
192 if (lqtL_testudata(L, -1, t)) {
193 //cout << obj << " reused" << endl;
194 lua_remove(L, -2);
195 return;
196 } else {
197 //cout << luaL_typename(L, -1) << " testudata failed " << lua_touserdata(L, -1) << ' ' << lqtL_topointer(L, -1) << endl;
199 lua_pop(L, 2);
202 if (1) {
203 lqtL_pushpointer(L, obj, t);
204 } else {
205 const void **objp = (const void**)lua_newuserdata(L, sizeof(const void *));
206 *objp = 0;
207 lua_getfield(L, LUA_REGISTRYINDEX, t);
208 if (lua_istable(L, -1)) {
209 lua_setmetatable(L, -2);
210 } else {
211 //cout << "NO metatable given" << endl;
212 lua_pop(L, 1);
213 // TODO: add a fallback?
215 *objp = obj;
216 //cout << "pushed " << objp << ' ' << obj << endl;
218 //cout << lua_gettop(L) << endl;
219 if (1) {
220 lqtL_setpointer(L, -1, obj);
221 } else {
222 lua_getfield(L, LUA_REGISTRYINDEX, LQT_POINTERS);
223 lua_pushlightuserdata(L, const_cast<void *>(obj));
224 lua_pushvalue(L, -3);
225 lua_settable(L, -3);
226 lua_pop(L, 1);
228 //cout << lua_gettop(L) << endl;
230 void lqtL_passudata (lua_State *L, const void *obj, const char *t) {
231 //cout << "passing: " << obj << " " << t << endl;
232 lqtL_pushudata(L, obj, t);
233 lqtL_manageudata(L, -1);
237 int lqtL_derivesfrom (lua_State *L, int i, const char *t) {
238 int ret = 0;
239 int oldtop = lua_gettop(L);
240 i = LQT_FIXEDINDEX(i);
242 if (!lua_istable(L, i)) {
243 return 0;
246 luaL_checkstack(L, 1, "cannot grow stack for checking object type");
248 //qDebug() << "given a table" << lua_topointer(L, i);
249 lua_getfield(L, LUA_REGISTRYINDEX, t);
250 //qDebug() << "table" << t << lua_topointer(L, -1);
251 ret = lua_equal(L, i, -1);
252 //qDebug() << "same as" << t << "?" << (bool)ret;
255 lua_settop(L, oldtop);
257 return ret;
258 // */
260 if (!ret) {
261 lua_pop(L, 1);
262 luaL_checkstack(L, 13, "cannot grow stack for checking object type"); // FIXME: is it enough?
263 lua_getfield(L, i, "__base");
265 if (!lua_istable(L, -1)) {
266 lua_pop(L, 1);
267 ret = 0;
268 } else {
269 lua_getfield(L, -1, t);
270 ret = lua_isnil(L, -1)?0:1;
271 //if (ret) qDebug() << (lua_toboolean(L, -1)?"directly":"INDIRECTLY") << "derives from" << t;
272 // DANGER: order of control expression is important
273 while ((ret == 0) && (lua_next(L, -2) != 0)) {
274 if (!lua_istable(L, -1)) {
275 lua_pop(L, 1);
276 lua_pushvalue(L, -1);
277 lua_gettable(L, LUA_REGISTRYINDEX);
278 if (lua_istable(L, -1)) {
279 lua_pushvalue(L, -2);
280 lua_pushvalue(L, -2);
281 lua_settable(L, -5);
284 if (lua_istable(L, -1)) {
285 ret = lqtL_derivesfrom(L, -1, t);
287 lua_pop(L, 1);
292 lua_settop(L, oldtop);
294 return ret;
297 bool lqtL_testudata (lua_State *L, int i, const char *t) {
298 //qDebug() << "================ testudata" << t;
299 //luaL_checkstack(L, 99, "");
300 i = LQT_FIXEDINDEX(i);
301 bool ret = false;
302 if (lua_getmetatable(L, i)) {
303 //SEE_STACK(L, pippo);
304 //SEE_STACK(L, pippo);
305 if (0) {
306 lua_getfield(L, LUA_REGISTRYINDEX, "QEvent*");
307 if (0 && lua_istable(L, -1)) {
308 lua_getfield(L, -1, "__qtype");
309 //SEE_STACK(L, pippo);
310 lua_pop(L, 1);
312 lua_pop(L, 2);
314 ret = (bool) lqtL_derivesfrom(L, -1, t);
316 //qDebug() << "derives?" << ret;
317 if (!ret && lqtL_derivesfrom(L, -1, "void*")) {
318 //cout << "checking for a generic void* pointer" << endl;
320 luaL_checkstack(L, 3, "cannot check void* real type");
321 lua_getfenv(L, i);
322 lua_getfield(L, -1, "__unknown_type");
323 //TODO: assign dynamically?
324 lua_pushstring(L, t);
325 ret = (bool)lua_equal(L, -1, -2);
326 lua_pop(L, 3);
327 // */
328 // FIXME: deleting makes QMetaObjects not work
329 //ret = true;
331 lua_pop(L, 1);
332 } else {
334 //cout << t << (ret?"":" NOT") <<" found" << endl;
335 return ret;
337 bool ret = false;
338 int oldtop = lua_gettop(L);
339 lua_getfield(L, LUA_REGISTRYINDEX, t);
340 if (lua_getmetatable(L, i)) {
341 ret = (bool)lua_equal(L, -1, -2);
342 if (!ret) {
343 lua_remove(L, -2);
344 ret = lqTL_derivesfrom(L, -1, t);
347 lua_settop(L, oldtop);
348 return ret;
353 int lqtL_pushtype (lua_State *L, int i) {
354 int type = lua_type(L, i);
355 if (type != LUA_TUSERDATA) {
356 lua_pushstring(L, lua_typename(L, type));
357 } else {
358 lua_getfield(L, i, "__qtype");
359 if (!lua_isstring(L, -1)) {
360 lua_pop(L, 1);
361 lua_pushstring(L, "<unknown>");
364 return 1;
367 void * lqtL_checkudata (lua_State *L, int i, const char *t) {
368 if (lqtL_testudata(L, i, t)) {
369 return lua_touserdata(L, i);
370 } else {
371 lua_pushstring(L, "Fatal error: userdata type mismatch. requested ");
372 lua_pushstring(L, t);
373 lua_pushstring(L, " found ");
374 lqtL_pushtype(L, i);
375 lua_concat(L, 4);
376 lua_error(L);
378 return 0;
380 //*/
381 void * lqtL_toudata (lua_State *L, int i, const char *t) {
382 void * ret = NULL;
383 if (lqtL_testudata(L, i, t)) {
384 ret = *static_cast<void**>(lua_touserdata(L, i));
386 return ret;
389 void lqtL_pushenum (lua_State *L, int v, const char *e) {
390 lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);
391 if (lua_istable(L, -1)) {
392 //qDebug() << "LQT_ENUMS is a table";
393 lua_getfield(L, -1, e);
394 lua_remove(L, -2);
395 } else {
396 //qDebug() << "LQT_ENUMS is NOT a table";
398 lua_pushinteger(L, v);
399 if (lua_istable(L, -2)) {
400 //qDebug() << "getting translation";
401 lua_gettable(L, -2);
402 } else {
403 //qDebug() << "no translation table for" << e;
405 lua_remove(L, -2);
407 bool lqtL_isenum (lua_State *L, int i, const char *e) {
408 bool ret = false;
409 if (lua_type(L, i)==LUA_TNUMBER) {
410 ret = (lua_tointeger(L, i)==lua_tonumber(L, i));
411 } else if (lua_type(L, i)==LUA_TSTRING) {
412 lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);
413 if (lua_istable(L, -1)) {
414 lua_getfield(L, -1, e);
415 lua_remove(L, -2);
417 lua_pushvalue(L, i);
418 if (lua_istable(L, -2)) {
419 lua_gettable(L, -2);
421 if (lua_type(L, -1)==LUA_TNUMBER) {
422 ret = (lua_tointeger(L, -1)==lua_tonumber(L, -1));
424 lua_pop(L, 2);
426 return ret;
428 int lqtL_toenum (lua_State *L, int i, const char *e) {
429 int ret = -1;
430 if (lua_type(L, i)==LUA_TNUMBER) {
431 ret = lua_tointeger(L, i);
432 } else if (lua_type(L, i)==LUA_TSTRING) {
433 lua_getfield(L, LUA_REGISTRYINDEX, LQT_ENUMS);
434 if (lua_istable(L, -1)) {
435 lua_getfield(L, -1, e);
436 lua_remove(L, -2);
438 lua_pushvalue(L, i);
439 if (lua_istable(L, -2)) {
440 lua_gettable(L, -2);
442 if (lua_type(L, -1)==LUA_TNUMBER) {
443 ret = lua_tointeger(L, -1);
445 lua_pop(L, 2);
447 return ret;
450 int lqtL_baseindex (lua_State *L, int index, int key) {
451 int ret = 0;
452 int oldtop = lua_gettop(L);
453 index = LQT_FIXEDINDEX(index);
454 key = LQT_FIXEDINDEX(key);
456 if (!lua_istable(L, index)) {
457 return 0;
460 luaL_checkstack(L, 1, "cannot grow stack for retrieving member");
462 lua_pushvalue(L, key);
463 lua_gettable(L, index);
465 if (!lua_isnil(L, -1)) {
466 ret = 1;
467 } else {
468 luaL_checkstack(L, 7, "cannot grow stack for retrieving member"); // FIXME: is it enough?
469 lua_getfield(L, index, "__base");
471 if (!lua_istable(L, -1)) {
472 lua_pop(L, 2);
473 ret = 0;
474 } else {
475 lua_insert(L, -2);
476 // DANGER: order of control expression is important
477 while ((ret == 0) && (lua_next(L, -2) != 0)) {
478 if (!lua_istable(L, -1) && lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
479 lua_pop(L, 1);
480 lua_pushvalue(L, -1);
481 lua_gettable(L, LUA_REGISTRYINDEX);
482 if (lua_istable(L, -1)) {
483 lua_pushvalue(L, -2);
484 lua_pushvalue(L, -2);
485 lua_settable(L, -5);
488 if (lua_istable(L, -1)) {
489 ret = lqtL_baseindex(L, -1, key);
491 if (ret == 0) {
492 lua_pop(L, 1);
498 if (ret != 0) {
499 lua_insert(L, oldtop+1);
501 lua_settop(L, oldtop+ret);
503 return ret;
506 int lqtL_index (lua_State *L) {
507 lua_settop(L, 2);
508 luaL_checkstack(L, 1, "cannot grow stack for retrieving member");
509 if (!lua_getmetatable(L, 1)) {
510 return 0;
513 return lqtL_baseindex(L, 3, 2);
515 luaL_checkstack(L, 2, "cannot grow stack for retrieving member");
516 lua_getmetatable(L, 1);
517 if (lua_istable(L, -1)) {
518 lua_pushvalue(L, 2);
519 lua_gettable(L, -2);
520 } else {
521 lua_pushnil(L);
523 lua_remove(L, -2);
524 return 1;
528 int lqtL_newindex (lua_State *L) {
529 if (!lua_getmetatable(L, 1)) {
530 return 0;
532 if (lua_istable(L, -1)) {
533 lua_pushvalue(L, 2);
534 lua_pushvalue(L, 3);
535 lua_settable(L, -3);
536 lua_pop(L, 1);
538 return 0;
541 int lqtL_gc (lua_State *L) {
542 if (!lua_isuserdata(L, 1)) return 0;
544 lua_getfenv(L, 1);
545 if (lua_istable(L, -1)) {
546 lua_getfield(L, -1, "__gc");
547 if (lua_isfunction(L, -1)) {
548 //cout << "found fenv gc " << lua_topointer(L, -1) << endl;
549 lua_pushvalue(L, 1);
550 lua_call(L, 1, 0);
551 } else {
552 //cout << "NOT found fenv gc" << endl;
553 lua_pop(L, 1);
556 lua_pop(L, 1);
558 // FIXME: this is useless, isn't it?
559 void **p = static_cast<void**>(lua_touserdata(L, 1));
560 *p = 0;
562 return 0;