2 * Copyright (c) 2007-2008 Mauro Iazzi
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
27 #include "lqt_common.hpp"
32 static void lqtL_getenumtable (lua_State
*L
) {
33 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
34 if (lua_isnil(L
, -1)) {
38 lua_setfield(L
, LUA_REGISTRYINDEX
, LQT_ENUMS
);
42 static void lqtL_getpointertable (lua_State
*L
) {
43 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
); // (1) get storage for pointers
44 if (lua_isnil(L
, -1)) { // (1) if there is not
45 lua_pop(L
, 1); // (0) pop the nil value
46 lua_newtable(L
); // (1) create a new one
47 lua_newtable(L
); // (2) create an empty metatable
48 lua_pushstring(L
, "v"); // (3) push the mode value: weak values are enough
49 lua_setfield(L
, -2, "__mode"); // (2) set the __mode field
50 lua_setmetatable(L
, -2); // (1) set it as the metatable
51 lua_pushvalue(L
, -1); // (2) duplicate the new pointer table
52 lua_setfield(L
, LUA_REGISTRYINDEX
, LQT_POINTERS
); // (1) put one copy as storage
56 static void lqtL_getreftable (lua_State
*L
) {
57 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_REFS
); // (1) get storage for pointers
58 if (lua_isnil(L
, -1)) { // (1) if there is not
59 lua_pop(L
, 1); // (0) pop the nil value
60 lua_newtable(L
); // (1) create a new one
61 lua_newtable(L
); // (2) create an empty metatable
62 lua_pushstring(L
, "v"); // (3) push the mode value: weak values are enough
63 lua_setfield(L
, -2, "__mode"); // (2) set the __mode field
64 lua_setmetatable(L
, -2); // (1) set it as the metatable
65 lua_pushvalue(L
, -1); // (2) duplicate the new pointer table
66 lua_setfield(L
, LUA_REGISTRYINDEX
, LQT_REFS
); // (1) put one copy as storage
70 void * lqtL_getref (lua_State
*L
, size_t sz
, bool weak
) {
72 lqtL_getreftable(L
); // (1)
73 ret
= lua_newuserdata(L
, sz
); // (2)
75 lua_newtable(L); // (3)
76 lua_getglobal(L, "DEBUG"); // (4)
77 lua_setfield(L, -2, "__gc"); // (3)
78 lua_setmetatable(L, -2); // (2)
81 lua_rawseti(L
, -2, 1+lua_objlen(L
, -2)); // (1)
83 lua_pushinteger(L
, 1+lua_objlen(L
, -2)); // (3)
84 lua_settable(L
, -3); // (1)
90 bool * lqtL_toboolref (lua_State
*L
, int index
) {
91 bool tmp
= lua_toboolean(L
, index
) == 1;
92 bool *ret
= (bool*)lqtL_getref(L
, sizeof(bool), true);
97 int * lqtL_tointref (lua_State
*L
, int index
) {
98 int tmp
= lua_tointeger(L
, index
);
99 int *ret
= (int*)lqtL_getref(L
, sizeof(int), false);
104 void lqtL_pusharguments (lua_State
*L
, char **argv
) {
107 for (i
=0;*argv
/* fix the maximum number? */;argv
++,i
++) {
108 lua_pushstring(L
, *argv
);
109 lua_rawseti(L
, -2, i
+1);
114 char ** lqtL_toarguments (lua_State
*L
, int index
) {
115 char ** ret
= (char**)lqtL_getref(L
, sizeof(char*)*(lua_objlen(L
, index
)+1), false);
116 const char *str
= NULL
;
120 lua_rawgeti(L
, index
, i
+1);
121 if (!lua_isstring(L
, -1)) {
122 str
= NULL
; strlen
= 0;
127 str
= lua_tolstring(L
, -1, &strlen
);
128 ret
[i
] = (char*)lqtL_getref(L
, sizeof(char)*(strlen
+1), false);
129 strncpy(ret
[i
], str
, strlen
+1);
136 int lqtL_createenum (lua_State
*L
, lqt_Enum e
[], const char *n
) {
137 luaL_Reg empty
[] = { { 0, 0 } };
139 lqtL_getenumtable(L
); // (1)
140 lua_newtable(L
); // (2)
141 lua_pushvalue(L
, -1); // (3)
142 lua_setfield(L
, -3, n
); // (2)
143 while ( (l
->name
!=0) ) { // (2)
144 lua_pushstring(L
, l
->name
); // (3)
145 lua_pushinteger(L
, l
->value
); // (4)
146 lua_settable(L
, -3); // (2)
147 lua_pushinteger(L
, l
->value
); // (3)
148 lua_pushstring(L
, l
->name
); // (4)
149 lua_settable(L
, -3); // (2)
152 lua_pop(L
, 2); // (0)
154 luaL_register(L
, n
, empty
); // (1)
155 while ( (l
->name
!=0) ) { // (1)
156 lua_pushstring(L
, l
->name
); // (2)
157 lua_pushinteger(L
, l
->value
); // (3)
158 lua_settable(L
, -3); // (1)
159 lua_pushinteger(L
, l
->value
); // (2)
160 lua_pushstring(L
, l
->name
); // (3)
161 lua_settable(L
, -3); // (1)
164 lua_pop(L
, 1); // (0)
168 int lqtL_createenumlist (lua_State
*L
, lqt_Enumlist list
[]) {
169 while (list
->enums
!=0 && list
->name
!=0) {
170 lqtL_createenum(L
, list
->enums
, list
->name
); // (0)
176 static int lqtL_gcfunc (lua_State
*L
) {
177 if (!lua_isuserdata(L
, 1) || lua_islightuserdata(L
, 1)) return 0;
178 lua_getfenv(L
, 1); // (1)
179 if (!lua_istable(L
, -1)) {
180 lua_pop(L
, 1); // (0)
183 lua_getfield(L
, -1, "__gc"); // (2)
184 lua_remove(L
, -2); // (1)
185 if (!lua_isfunction(L
, -1)) {
186 lua_pop(L
, 1); // (0)
189 lua_pushvalue(L
, 1); // (2)
190 if (lqtL_pcall(L
, 1, 0, 0)) { // (-2;+1/+0)
197 static int lqtL_newindexfunc (lua_State
*L
) {
198 if (!lua_isuserdata(L
, 1) && lua_islightuserdata(L
, 1)) return 0;
199 lua_getmetatable(L
, 1);
200 lua_pushliteral(L
, "__set");
202 if (lua_istable(L
, -1)) {
205 if (lua_isfunction(L
, -1)) {
206 lua_CFunction setter
= lua_tocfunction(L
, -1);
207 if (!setter
) return luaL_error(L
, "Invalid setter %s", lua_tostring(L
, 2));
211 lua_settop(L
, 3); // (=3)
212 lua_getfenv(L
, 1); // (+1)
213 if (!lua_istable(L
, -1)) {
214 lua_pop(L
, 1); // (+0)
217 lua_remove(L
, 1); // (+0)
218 lua_insert(L
, 1); // (+0)
219 lua_rawset(L
, 1); // (-2)
223 int lqtL_getoverload (lua_State
*L
, int index
, const char *name
) {
224 luaL_checkstack(L
, 2, "no space to grow");
225 if (lua_isuserdata(L
, index
) && !lua_islightuserdata(L
, index
)) {
226 lua_getfenv(L
, index
); // (1)
227 lua_getfield(L
, -1, name
); // (2)
228 lua_remove(L
, -2); // (1)
230 lua_pushnil(L
); // (1)
235 static int lqtL_indexfunc (lua_State
*L
) {
237 if (lua_isuserdata(L
, 1) && !lua_islightuserdata(L
, 1)) {
238 lua_getmetatable(L
, 1);
239 lua_pushliteral(L
, "__get");
241 if (lua_istable(L
, -1)) {
244 if (lua_isfunction(L
, -1)) {
245 lua_CFunction getter
= lua_tocfunction(L
, -1);
246 if (!getter
) return luaL_error(L
, "Invalid getter %s", lua_tostring(L
, 2));
251 lua_getfenv(L
, 1); // (1)
252 lua_pushvalue(L
, 2); // (2)
253 lua_gettable(L
, -2); // (2)
254 if (!lua_isnil(L
, -1)) {
258 lua_pop(L
, 2); // (0)
260 lua_pushnil(L
); // (+1)
261 while (!lua_isnone(L
, lua_upvalueindex(i
))) { // (+1)
262 lua_pop(L
, 1); // (+0)
263 lua_pushvalue(L
, 2); // (+1)
265 lua_rawget(L
, lua_upvalueindex(i
)); // (+1)
267 lua_gettable(L
, lua_upvalueindex(i
)); // (+1)
269 if (!lua_isnil(L
, -1)) break;
275 static int lqtL_pushindexfunc (lua_State
*L
, const char *name
, lqt_Base
*bases
) {
277 luaL_newmetatable(L
, name
); // (1)
278 while (bases
->basename
!=NULL
) {
279 luaL_newmetatable(L
, bases
->basename
); // (upnum)
283 lua_pushcclosure(L
, lqtL_indexfunc
, upnum
); // (1)
287 static int lqtL_ctor_helper(lua_State
*L
) {
288 lua_getfield(L
, 1, "new");
290 lua_call(L
, lua_gettop(L
)-1, LUA_MULTRET
);
291 return lua_gettop(L
);
294 static int lqtL_local_ctor(lua_State
*L
) {
295 lua_pushvalue(L
, lua_upvalueindex(1)); // (+1)
296 lua_getfield(L
, -1, "new"); // (+2)
297 lua_insert(L
, 1); // (+2)
298 lua_pop(L
, 1); // (+1)
299 lua_call(L
, lua_gettop(L
)-1, LUA_MULTRET
); // (X)
300 lua_getfield(L
, 1, "delete"); // (X+1)
301 lua_setfield(L
, 1, "__gc"); // (X)
302 return lua_gettop(L
);
305 int lqtL_createclass (lua_State
*L
, const char *name
, luaL_Reg
*mt
, luaL_Reg
*getters
, luaL_Reg
*setters
, lqt_Base
*bases
) {
307 char *new_name
= NULL
;
308 lqt_Base
*bi
= bases
;
309 luaL_newmetatable(L
, name
); // (1)
310 luaL_register(L
, NULL
, mt
); // (1)
312 lua_pushstring(L
, name
); // (2) FIXME: remove
313 lua_pushinteger(L
, 0); // (3) FIXME: remove
314 lua_settable(L
, -3); // (1) FIXME: remove
315 while (bi
->basename
!=NULL
) {
316 lua_pushstring(L
, bi
->basename
); // (2) FIXME: remove
317 lua_pushinteger(L
, bi
->offset
); // (3) FIXME: remove
318 lua_settable(L
, -3); // (1) FIXME: remove
324 luaL_register(L
, NULL
, getters
);
325 lua_setfield(L
, -2, "__get");
329 luaL_register(L
, NULL
, setters
);
330 lua_setfield(L
, -2, "__set");
334 lqtL_pushindexfunc(L
, name
, bases
); // (2)
335 lua_setfield(L
, -2, "__index"); // (1)
336 lua_pushcfunction(L
, lqtL_newindexfunc
); // (2)
337 lua_setfield(L
, -2, "__newindex"); // (1)
338 lua_pushcfunction(L
, lqtL_gcfunc
); // (2)
339 lua_setfield(L
, -2, "__gc"); // (1)
340 lua_pushstring(L
, name
);
341 lua_setfield(L
, -2, "__type");
343 // set it as its own metatable
344 lua_pushvalue(L
, -1); // (2)
345 lua_setmetatable(L
, -2); // (1)
346 lua_pop(L
, 1); // (0)
348 new_name
= (char*)malloc(len
*sizeof(char));
349 strncpy(new_name
, name
, len
);
350 new_name
[len
-1] = '\0';
351 luaL_register(L
, new_name
, mt
); // (1)
354 lua_newtable(L
); // (2)
355 lua_pushcfunction(L
, lqtL_ctor_helper
); // (3)
356 lua_setfield(L
, -2, "__call"); // (2)
357 lua_setmetatable(L
, -2); // (1)
358 lua_pushvalue(L
, -1); // (2)
359 lua_pushcclosure(L
, lqtL_local_ctor
, 1); // (2)
360 lua_setfield(L
, -2, "new_local");
361 lua_pop(L
, 1); // (0)
363 lua_pushlstring(L, name, strlen(name)-1); // (1)
364 lua_newtable(L); // (2)
365 luaL_newmetatable(L, name); // (3)
366 lua_setmetatable(L, -2); // (2)
367 // don't register again but use metatable
368 //luaL_register(L, NULL, mt); // (2)
369 lua_settable(L, LUA_GLOBALSINDEX); // (0)
374 bool lqtL_isinteger (lua_State
*L
, int i
) {
375 if (lua_type(L
, i
)==LUA_TNUMBER
) {
376 return lua_tointeger(L
, i
)==lua_tonumber(L
, i
);
381 bool lqtL_isnumber (lua_State
*L
, int i
) {
382 return lua_type(L
, i
)==LUA_TNUMBER
;
384 bool lqtL_isstring (lua_State
*L
, int i
) {
385 return lua_type(L
, i
)==LUA_TSTRING
;
387 bool lqtL_isboolean (lua_State
*L
, int i
) {
388 return lua_type(L
, i
)==LUA_TBOOLEAN
;
390 bool lqtL_missarg (lua_State
*L
, int index
, int n
) {
393 for (i
=index
;i
<index
+n
;i
++) {
394 if (!lua_isnoneornil(L
, i
)) {
402 static void CS(lua_State
*L
) {
403 std::cerr
<< "++++++++++" << std::endl
;
404 for (int i
=1;i
<=lua_gettop(L
);i
++) {
405 std::cerr
<< luaL_typename(L
, i
) << " " << lua_touserdata(L
, i
) << std::endl
;
407 std::cerr
<< "----------" << std::endl
;
410 static void lqtL_ensurepointer (lua_State
*L
, const void *p
) { // (+1)
411 lqtL_getpointertable(L
); // (1)
412 lua_pushlightuserdata(L
, const_cast<void*>(p
)); // (2)
413 lua_gettable(L
, -2); // (2)
414 if (lua_isnil(L
, -1)) { // (2)
415 lua_pop(L
, 1); // (1)
416 const void **pp
= static_cast<const void**>(lua_newuserdata(L
, sizeof(void*))); // (2)
418 lua_newtable(L
); // (3)
419 lua_setfenv(L
, -2); // (2)
420 lua_pushlightuserdata(L
, const_cast<void*>(p
)); // (3)
421 lua_pushvalue(L
, -2); // (4)
422 lua_settable(L
, -4); // (2)
424 //const void **pp = static_cast<const void**>(lua_touserdata(L, -1)); // (2)
425 //if (pp!=NULL) *pp = p; // (2)
428 lua_remove(L
, -2); // (1)
431 void lqtL_register (lua_State
*L
, const void *p
) { // (+0)
432 lqtL_ensurepointer(L
, p
);
436 void lqtL_unregister (lua_State
*L
, const void *p
) {
437 lqtL_getpointertable(L
); // (1)
438 lua_pushlightuserdata(L
, const_cast<void*>(p
)); // (2)
439 lua_gettable(L
, -2); // (2)
440 if (lua_isuserdata(L
, -1)) {
441 const void **pp
= static_cast<const void**>(lua_touserdata(L
, -1)); // (2)
444 lua_pop(L
, 1); // (1)
445 lua_pushlightuserdata(L
, const_cast<void*>(p
)); // (2)
446 lua_pushnil(L
); // (3)
447 lua_settable(L
, -3); // (1)
448 lua_pop(L
, 1); // (0)
451 void lqtL_pushudata (lua_State
*L
, const void *p
, const char *name
) {
452 bool already
= false;
453 lqtL_ensurepointer(L
, p
); // (1)
454 if (lua_getmetatable(L
, -1)) {
456 lua_pop(L
, 1); // (1)
457 lua_getfield(L
, -1, name
); // (2)
458 already
= lua_toboolean(L
, -1) == 1; // (2)
459 lua_pop(L
, 1); // (1)
464 luaL_newmetatable(L
, name
); // (2)
465 lua_setmetatable(L
, -2); // (1)
470 void lqtL_passudata (lua_State
*L
, const void *p
, const char *name
) {
471 lqtL_pushudata(L
, p
, name
);
472 // used only when passing temporaries - should be deleted afterwards
473 lua_getfield(L
, -1, "delete");
474 lua_setfield(L
, -2, "__gc");
478 void lqtL_copyudata (lua_State
*L
, const void *p
, const char *name
) {
479 luaL_newmetatable(L
, name
);
480 lua_pushstring(L
, "new");
482 if (lua_isnil(L
, -1)) {
483 std::cerr
<< "cannot copy " << name
<< std::endl
;
488 lqtL_pushudata(L
, p
, name
);
489 if (lqtL_pcall(L
, 1, 1, 0)) {
490 std::cerr
<< "error copying " << name
<< std::endl
;
494 // Enable autodeletion for copied stuff
495 lua_getfield(L
, -1, "delete");
496 lua_setfield(L
, -2, "__gc");
501 void *lqtL_toudata (lua_State
*L
, int index
, const char *name
) {
503 if (!lqtL_testudata(L
, index
, name
)) return 0;
504 void **pp
= static_cast<void**>(lua_touserdata(L
, index
));
506 lua_getfield(L
, index
, name
);
507 ret
= (void*)(lua_tointeger(L
, -1) + (char*)ret
);
512 void lqtL_eraseudata (lua_State
*L
, int index
, const char *name
) {
514 if (name
!=NULL
&& !lqtL_testudata(L
, index
, name
)) return;
515 void **pp
= static_cast<void**>(lua_touserdata(L
, index
));
518 lqtL_getpointertable(L
); // (1)
519 lua_pushlightuserdata(L
, p
); // (2)
520 lua_pushnil(L
); // (3)
521 lua_settable(L
, -3); // (1)
526 bool lqtL_testudata (lua_State
*L
, int index
, const char *name
) {
527 if (!lua_isuserdata(L
, index
) || lua_islightuserdata(L
, index
)) return false;
528 lua_getfield(L
, index
, name
);
529 if (lua_isnil(L
, -1)) {
537 const char * lqtL_pushtrace(lua_State
*L
) {
538 lua_getglobal(L
, "debug");
539 lua_getfield(L
, -1, "traceback");
542 return lua_tostring(L
, -1);
545 void lqtL_pushenum (lua_State
*L
, int value
, const char *name
) {
546 lqtL_getenumtable(L
);
547 lua_getfield(L
, -1, name
);
549 if (!lua_istable(L
, -1)) {
554 lua_pushnumber(L
, value
);
559 bool lqtL_isenum (lua_State
*L
, int index
, const char *name
) {
561 if (!lua_isstring(L
, index
)) return false;
562 lqtL_getenumtable(L
);
563 lua_getfield(L
, -1, name
);
564 if (!lua_istable(L
, -1)) {
569 lua_pushvalue(L
, index
);
571 ret
= !lua_isnil(L
, -1);
576 int lqtL_toenum (lua_State
*L
, int index
, const char *name
) {
578 // index = LQT_TOPOSITIVE(L, index);
579 lqtL_getenumtable(L
); // (1)
580 lua_getfield(L
, -1, name
); // (2)
581 if (lua_isnil(L
, -1)) {
585 lua_pushvalue(L
, index
); // (3)
586 lua_gettable(L
, -2); // (3)
587 if (lqtL_isinteger(L
, -1)) {
588 ret
= lua_tointeger(L
, -1); // (3)
590 ret
= lua_tointeger(L
, index
); // (3)
592 lua_pop(L
, 3); // (0)
596 int lqtL_getflags (lua_State
*L
, int index
, const char *name
) {
600 if (lqtL_isinteger(L
, index
)) return lua_tointeger(L
, index
);
601 if (!lua_istable(L
, index
)) return 0;
602 lqtL_getenumtable(L
); // (1)
603 lua_getfield(L
, -1, name
); // (2)
604 if (!lua_istable(L
, -1)) {
610 lua_remove(L
, -2); // (1)
611 eindex
= lua_gettop(L
);
612 for (i
=1;;i
++) { // (1)
613 lua_rawgeti(L
, index
, i
); // (2)
614 if (lua_type(L
, -1)!=LUA_TSTRING
) {
615 lua_pop(L
, 1); // (1)
618 lua_gettable(L
, eindex
); // (2)
619 ret
= ret
| (int)lua_tointeger(L
, -1);
620 lua_pop(L
, 1); // (1)
624 lua_pop(L
, 1); // (0)
630 void lqtL_pushflags (lua_State
*L
, int value
, const char *name
) {
632 lua_newtable(L
); // (1) return value
633 lqtL_getenumtable(L
); // (2)
634 lua_getfield(L
, -1, name
); // (3)
635 lua_remove(L
, -2); // (2) stack: ret, enumtable
636 lua_pushnil(L
); // (3) first index
637 while (lua_next(L
, -2) != 0) { // (4) stack: ret, enumtable, index, value
638 //if (lua_isnumber(L, -2)) {
639 //qDebug() << ((void*)lua_tointeger(L, -2))
640 //<< ((void*)value) << (void*)(lua_tointeger(L, -2)&value)
641 //<< ((lua_tointeger(L, -2)&value)==lua_tointeger(L, -2)) << lua_tostring(L, -1);
643 if (lua_isnumber(L
, -2) &&
644 ((lua_tointeger(L
, -2)&value
)==lua_tointeger(L
, -2))) {
645 // (4) if index is the value
646 lua_rawseti(L
, -4, index
); // (3) the string is put into the ret table
647 index
= index
+ 1; // (3) the size of the ret table has increased
649 lua_pop(L
, 1); // (3) pop the value
652 // (2) lua_next pops the vale and pushes nothing at the end of the iteration
653 // (2) stack: ret, enumtable
654 lua_pop(L
, 1); // (1) stack: ret
658 int lqtL_touintarray (lua_State
*L
) {
659 unsigned int *p
= NULL
;
662 n
= lua_objlen(L
, -1);
663 nb
= (n
+ 1) * sizeof(unsigned int);
664 p
= (unsigned int *)lua_newuserdata(L
, nb
);
666 lua_rawgeti(L
, -2, i
);
667 p
[i
-1] = lua_tointeger(L
, -1);
675 int lqtL_pcall_debug_default (lua_State
*L
, int narg
, int nres
, int err
) {
677 std::cerr
<< "entering a pcall" << std::endl
;
678 status
= lua_pcall(L
, narg
, nres
, err
);
679 std::cerr
<< "pcall finished with status " << status
<< std::endl
;
683 int lqtL_pcall_debug (lua_State
*L
, int narg
, int nres
, int err
) {
685 lua_getfield(L
, LUA_REGISTRYINDEX
, LQT_PCALL
);
686 lqt_PCallPtr pcall
= (lqt_PCallPtr
)lua_touserdata(L
, -1);
689 status
= pcall(L
, narg
, nres
, err
);
691 status
= lqtL_pcall_debug_default(L
, narg
, nres
, err
);
696 void lqtL_pushudatatype (lua_State
*L
, int index
) {
697 if (!lua_isuserdata(L
, index
) || lua_islightuserdata(L
, index
)) {
698 lua_pushstring(L
, luaL_typename(L
, index
));
700 lua_getfield(L
, index
, "__type");
701 if (lua_isnil(L
, -1)) {
703 lua_pushstring(L
, luaL_typename(L
, index
));
708 const char * lqtL_getarglist (lua_State
*L
) {
709 int args
= lua_gettop(L
);
710 lua_checkstack(L
, args
* 2);
711 lua_pushliteral(L
, "");
712 for(int i
= 1; i
<= args
; i
++) {
713 lqtL_pushudatatype(L
, i
);
715 lua_pushliteral(L
, ", ");
717 lua_concat(L
, 2*args
- 1);
718 return lua_tostring(L
, -1);
721 const char * lqtL_source(lua_State
*L
, int idx
) {
722 static char buf
[1024]; // TODO: try something better
724 lua_pushvalue(L
, idx
);
725 lua_getinfo(L
, ">S", &ar
);
726 if (ar
.source
[0] != '@') {
727 sprintf(buf
, "%s", ar
.source
);
729 sprintf(buf
, "%s %s:%d", ar
.name
, ar
.source
, ar
.linedefined
);
734 bool lqtL_is_super(lua_State
*L
, int idx
) {
735 lua_getfield(L
, LUA_GLOBALSINDEX
, LQT_SUPER
);
736 void *super
= lua_touserdata(L
, -1);
737 void *comp
= lua_touserdata(L
, idx
);
738 bool ret
= lua_equal(L
, -1, idx
);
743 void lqtL_register_super(lua_State
*L
) {
744 lua_getfield(L
, LUA_GLOBALSINDEX
, LQT_SUPER
);
745 if (lua_isnil(L
, -1)) {
746 void *ud
= lua_newuserdata(L
, sizeof(int));
747 lua_setfield(L
, LUA_GLOBALSINDEX
, LQT_SUPER
);
753 // returns true if the value at index `n` can be converted to `to_type`
754 bool lqtL_canconvert(lua_State
*L
, int n
, const char *to_type
) {
755 if (lqtL_testudata(L
, n
, to_type
))
757 int oldtop
= lua_gettop(L
);
758 luaL_getmetatable(L
, to_type
);
759 if (lua_isnil(L
, -1)) {
760 lua_settop(L
, oldtop
);
763 lua_getfield(L
, -1, "__test");
764 if (lua_isnil(L
, -1)) {
765 lua_settop(L
, oldtop
);
768 lqt_testfunc func
= (lqt_testfunc
) lua_touserdata(L
, -1);
769 lua_settop(L
, oldtop
);
773 // converts the value at index `n` to `to_type` and returns a pointer to it
774 void *lqtL_convert(lua_State
*L
, int n
, const char *to_type
) {
775 if (lqtL_testudata(L
, n
, to_type
))
776 return lqtL_toudata(L
, n
, to_type
);
777 int oldtop
= lua_gettop(L
);
778 luaL_getmetatable(L
, to_type
);
779 if (lua_isnil(L
, -1)) {
780 lua_settop(L
, oldtop
);
783 lua_getfield(L
, -1, "__convert");
784 if (lua_isnil(L
, -1)) {
785 lua_settop(L
, oldtop
);
788 lqt_convertfunc func
= (lqt_convertfunc
) lua_touserdata(L
, -1);
789 lua_settop(L
, oldtop
);
793 void lqtL_selfcheck(lua_State
*L
, void *self
, const char *name
) {
795 lua_pushfstring(L
, "Instance of %s has already been deleted in:\n", name
);