1 /* tolua: functions to check types.
2 ** Support code for Lua bindings.
3 ** Written by Waldemar Celes
4 ** TeCGraf/PUC-Rio
5 ** Apr 2003
6 ** $Id: $
7 */
8
9 /* This code is free software; you can redistribute it and/or modify it.
10 ** The software provided hereunder is on an "as is" basis, and
11 ** the author has no obligation to provide maintenance, support, updates,
12 ** enhancements, or modifications.
13 */
14
15 #include "tolua++.h"
16 #include "lauxlib.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20
21 /* a fast check if a is b, without parameter validation
22 i.e. if b is equal to a or a superclass of a. */
tolua_fast_isa(lua_State * L,int mt_indexa,int mt_indexb,int super_index)23 TOLUA_API int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index)
24 {
25 int result;
26 if (lua_rawequal(L, mt_indexa, mt_indexb))
27 result = 1;
28 else
29 {
30 if (super_index)
31 {
32 lua_pushvalue(L, super_index);
33 }
34 else
35 {
36 lua_pushliteral(L, "tolua_super");
37 lua_rawget(L, LUA_REGISTRYINDEX); /* stack: super */
38 }
39 lua_pushvalue(L, mt_indexa); /* stack: super mta */
40 lua_rawget(L, -2); /* stack: super super[mta] */
41 lua_pushvalue(L, mt_indexb); /* stack: super super[mta] mtb */
42 lua_rawget(L, LUA_REGISTRYINDEX); /* stack: super super[mta] typenameB */
43 lua_rawget(L, -2); /* stack: super super[mta] bool */
44 result = lua_toboolean(L, -1);
45 lua_pop(L, 3);
46 }
47 return result;
48 }
49
50 /* Push and returns the corresponding object typename */
tolua_typename(lua_State * L,int lo)51 TOLUA_API const char *tolua_typename(lua_State *L, int lo)
52 {
53 int tag = lua_type(L, lo);
54 if (tag == LUA_TNONE)
55 lua_pushstring(L, "[no object]");
56 else if (tag != LUA_TUSERDATA && tag != LUA_TTABLE)
57 lua_pushstring(L, lua_typename(L, tag));
58 else if (tag == LUA_TUSERDATA)
59 {
60 if (!lua_getmetatable(L, lo))
61 lua_pushstring(L, lua_typename(L, tag));
62 else
63 {
64 lua_rawget(L, LUA_REGISTRYINDEX);
65 if (!lua_isstring(L, -1))
66 {
67 lua_pop(L, 1);
68 lua_pushstring(L, "[undefined]");
69 }
70 }
71 }
72 else /* is table */
73 {
74 lua_pushvalue(L, lo);
75 lua_rawget(L, LUA_REGISTRYINDEX);
76 if (!lua_isstring(L, -1))
77 {
78 lua_pop(L, 1);
79 lua_pushstring(L, "table");
80 }
81 else
82 {
83 lua_pushstring(L, "class ");
84 lua_insert(L, -2);
85 lua_concat(L, 2);
86 }
87 }
88 return lua_tostring(L, -1);
89 }
90
tolua_error(lua_State * L,const char * msg,tolua_Error * err)91 TOLUA_API void tolua_error(lua_State *L, const char *msg, tolua_Error *err)
92 {
93 if (msg[0] == '#')
94 {
95 const char *expected = err->type;
96 const char *provided = tolua_typename(L, err->index);
97 if (msg[1] == 'f')
98 {
99 int narg = err->index;
100 if (err->array)
101 luaL_error(L, "%s\n argument #%d is array of '%s'; array of '%s' expected.\n",
102 msg + 2, narg, provided, expected);
103 else
104 luaL_error(L, "%s\n argument #%d is '%s'; '%s' expected.\n",
105 msg + 2, narg, provided, expected);
106 }
107 else if (msg[1] == 'v')
108 {
109 if (err->array)
110 luaL_error(L, "%s\n value is array of '%s'; array of '%s' expected.\n",
111 msg + 2, provided, expected);
112 else
113 luaL_error(L, "%s\n value is '%s'; '%s' expected.\n",
114 msg + 2, provided, expected);
115 }
116 }
117 else
118 luaL_error(L, msg);
119 }
120
121 /* the equivalent of lua_is* for usertable */
lua_isusertable(lua_State * L,int lo,const char * type)122 static int lua_isusertable(lua_State *L, int lo, const char *type)
123 {
124 int r = 0;
125 if (lo < 0)
126 lo = lua_gettop(L) + lo + 1;
127 lua_pushvalue(L, lo);
128 lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[t] */
129 if (lua_isstring(L, -1))
130 {
131 r = strcmp(lua_tostring(L, -1), type) == 0;
132 if (!r)
133 {
134 /* try const */
135 lua_pushstring(L, "const ");
136 lua_insert(L, -2);
137 lua_concat(L, 2);
138 r = lua_isstring(L, -1) && strcmp(lua_tostring(L, -1), type) == 0;
139 }
140 }
141 lua_pop(L, 1);
142 return r;
143 }
144
push_table_instance(lua_State * L,int lo)145 int push_table_instance(lua_State *L, int lo)
146 {
147
148 if (lua_istable(L, lo))
149 {
150
151 lua_pushstring(L, ".c_instance");
152 lua_gettable(L, lo);
153 if (lua_isuserdata(L, -1))
154 {
155
156 lua_replace(L, lo);
157 return 1;
158 }
159 else
160 {
161
162 lua_pop(L, 1);
163 return 0;
164 }
165 }
166 else
167 {
168 return 0;
169 }
170
171 return 0;
172 }
173
174 /* the equivalent of lua_is* for usertype */
lua_isusertype(lua_State * L,int lo,const char * type)175 static int lua_isusertype(lua_State *L, int lo, const char *type)
176 {
177 if (!lua_isuserdata(L, lo))
178 {
179 if (!push_table_instance(L, lo))
180 {
181 return 0;
182 }
183 }
184 {
185 /* check if it is of the same type */
186 int r;
187 const char *tn;
188 if (lua_getmetatable(L, lo)) /* if metatable? */
189 {
190 lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[mt] */
191 tn = lua_tostring(L, -1);
192 r = tn && (strcmp(tn, type) == 0);
193 lua_pop(L, 1);
194 if (r)
195 return 1;
196 else
197 {
198 /* check if it is a specialized class */
199 lua_pushstring(L, "tolua_super");
200 lua_rawget(L, LUA_REGISTRYINDEX); /* get super */
201 lua_getmetatable(L, lo);
202 lua_rawget(L, -2); /* get super[mt] */
203 if (lua_istable(L, -1))
204 {
205 int b;
206 lua_pushstring(L, type);
207 lua_rawget(L, -2); /* get super[mt][type] */
208 b = lua_toboolean(L, -1);
209 lua_pop(L, 3);
210 if (b)
211 return 1;
212 }
213 }
214 }
215 }
216 return 0;
217 }
218
tolua_isnoobj(lua_State * L,int lo,tolua_Error * err)219 TOLUA_API int tolua_isnoobj(lua_State *L, int lo, tolua_Error *err)
220 {
221 if (lua_gettop(L) < abs(lo))
222 return 1;
223 err->index = lo;
224 err->array = 0;
225 err->type = "[no object]";
226 return 0;
227 }
228
tolua_isboolean(lua_State * L,int lo,int def,tolua_Error * err)229 TOLUA_API int tolua_isboolean(lua_State *L, int lo, int def, tolua_Error *err)
230 {
231 if (def && lua_gettop(L) < abs(lo))
232 return 1;
233 if (lua_isnil(L, lo) || lua_isboolean(L, lo))
234 return 1;
235 err->index = lo;
236 err->array = 0;
237 err->type = "boolean";
238 return 0;
239 }
240
tolua_isnumber(lua_State * L,int lo,int def,tolua_Error * err)241 TOLUA_API int tolua_isnumber(lua_State *L, int lo, int def, tolua_Error *err)
242 {
243 if (def && lua_gettop(L) < abs(lo))
244 return 1;
245 if (lua_isnumber(L, lo))
246 return 1;
247 err->index = lo;
248 err->array = 0;
249 err->type = "number";
250 return 0;
251 }
252
tolua_isstring(lua_State * L,int lo,int def,tolua_Error * err)253 TOLUA_API int tolua_isstring(lua_State *L, int lo, int def, tolua_Error *err)
254 {
255 if (def && lua_gettop(L) < abs(lo))
256 return 1;
257 if (lua_isnil(L, lo) || lua_isstring(L, lo))
258 return 1;
259 err->index = lo;
260 err->array = 0;
261 err->type = "string";
262 return 0;
263 }
264
tolua_istable(lua_State * L,int lo,int def,tolua_Error * err)265 TOLUA_API int tolua_istable(lua_State *L, int lo, int def, tolua_Error *err)
266 {
267 if (def && lua_gettop(L) < abs(lo))
268 return 1;
269 if (lua_istable(L, lo))
270 return 1;
271 err->index = lo;
272 err->array = 0;
273 err->type = "table";
274 return 0;
275 }
276
tolua_isusertable(lua_State * L,int lo,const char * type,int def,tolua_Error * err)277 TOLUA_API int tolua_isusertable(lua_State *L, int lo, const char *type, int def, tolua_Error *err)
278 {
279 if (def && lua_gettop(L) < abs(lo))
280 return 1;
281 if (lua_isusertable(L, lo, type))
282 return 1;
283 err->index = lo;
284 err->array = 0;
285 err->type = type;
286 return 0;
287 }
288
tolua_isuserdata(lua_State * L,int lo,int def,tolua_Error * err)289 TOLUA_API int tolua_isuserdata(lua_State *L, int lo, int def, tolua_Error *err)
290 {
291 if (def && lua_gettop(L) < abs(lo))
292 return 1;
293 if (lua_isnil(L, lo) || lua_isuserdata(L, lo))
294 return 1;
295 err->index = lo;
296 err->array = 0;
297 err->type = "userdata";
298 return 0;
299 }
300
tolua_isvaluenil(lua_State * L,int lo,tolua_Error * err)301 TOLUA_API int tolua_isvaluenil(lua_State *L, int lo, tolua_Error *err)
302 {
303
304 if (lua_gettop(L) < abs(lo))
305 return 0; /* somebody else should chack this */
306 if (!lua_isnil(L, lo))
307 return 0;
308
309 err->index = lo;
310 err->array = 0;
311 err->type = "value";
312 return 1;
313 }
314
tolua_isvalue(lua_State * L,int lo,int def,tolua_Error * err)315 TOLUA_API int tolua_isvalue(lua_State *L, int lo, int def, tolua_Error *err)
316 {
317 if (def || abs(lo) <= lua_gettop(L)) /* any valid index */
318 return 1;
319 err->index = lo;
320 err->array = 0;
321 err->type = "value";
322 return 0;
323 }
324
tolua_isusertype(lua_State * L,int lo,const char * type,int def,tolua_Error * err)325 TOLUA_API int tolua_isusertype(lua_State *L, int lo, const char *type, int def, tolua_Error *err)
326 {
327 if (def && lua_gettop(L) < abs(lo))
328 return 1;
329 if (lua_isnil(L, lo) || lua_isusertype(L, lo, type))
330 return 1;
331 err->index = lo;
332 err->array = 0;
333 err->type = type;
334 return 0;
335 }
336
tolua_isvaluearray(lua_State * L,int lo,int dim,int def,tolua_Error * err)337 TOLUA_API int tolua_isvaluearray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
338 {
339 (void)dim;
340 if (!tolua_istable(L, lo, def, err))
341 return 0;
342 else
343 return 1;
344 }
345
tolua_isbooleanarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)346 TOLUA_API int tolua_isbooleanarray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
347 {
348 if (!tolua_istable(L, lo, def, err))
349 return 0;
350 else
351 {
352 int i;
353 for (i = 1; i <= dim; ++i)
354 {
355 lua_pushnumber(L, i);
356 lua_gettable(L, lo);
357 if (!(lua_isnil(L, -1) || lua_isboolean(L, -1)) &&
358 !(def && lua_isnil(L, -1)))
359 {
360 err->index = lo;
361 err->array = 1;
362 err->type = "boolean";
363 return 0;
364 }
365 lua_pop(L, 1);
366 }
367 }
368 return 1;
369 }
370
tolua_isnumberarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)371 TOLUA_API int tolua_isnumberarray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
372 {
373 if (!tolua_istable(L, lo, def, err))
374 return 0;
375 else
376 {
377 int i;
378 for (i = 1; i <= dim; ++i)
379 {
380 lua_pushnumber(L, i);
381 lua_gettable(L, lo);
382 if (!lua_isnumber(L, -1) &&
383 !(def && lua_isnil(L, -1)))
384 {
385 err->index = lo;
386 err->array = 1;
387 err->type = "number";
388 return 0;
389 }
390 lua_pop(L, 1);
391 }
392 }
393 return 1;
394 }
395
tolua_isstringarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)396 TOLUA_API int tolua_isstringarray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
397 {
398 if (!tolua_istable(L, lo, def, err))
399 return 0;
400 else
401 {
402 int i;
403 for (i = 1; i <= dim; ++i)
404 {
405 lua_pushnumber(L, i);
406 lua_gettable(L, lo);
407 if (!(lua_isnil(L, -1) || lua_isstring(L, -1)) &&
408 !(def && lua_isnil(L, -1)))
409 {
410 err->index = lo;
411 err->array = 1;
412 err->type = "string";
413 return 0;
414 }
415 lua_pop(L, 1);
416 }
417 }
418 return 1;
419 }
420
tolua_istablearray(lua_State * L,int lo,int dim,int def,tolua_Error * err)421 TOLUA_API int tolua_istablearray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
422 {
423 if (!tolua_istable(L, lo, def, err))
424 return 0;
425 else
426 {
427 int i;
428 for (i = 1; i <= dim; ++i)
429 {
430 lua_pushnumber(L, i);
431 lua_gettable(L, lo);
432 if (!lua_istable(L, -1) &&
433 !(def && lua_isnil(L, -1)))
434 {
435 err->index = lo;
436 err->array = 1;
437 err->type = "table";
438 return 0;
439 }
440 lua_pop(L, 1);
441 }
442 }
443 return 1;
444 }
445
tolua_isuserdataarray(lua_State * L,int lo,int dim,int def,tolua_Error * err)446 TOLUA_API int tolua_isuserdataarray(lua_State *L, int lo, int dim, int def, tolua_Error *err)
447 {
448 if (!tolua_istable(L, lo, def, err))
449 return 0;
450 else
451 {
452 int i;
453 for (i = 1; i <= dim; ++i)
454 {
455 lua_pushnumber(L, i);
456 lua_gettable(L, lo);
457 if (!(lua_isnil(L, -1) || lua_isuserdata(L, -1)) &&
458 !(def && lua_isnil(L, -1)))
459 {
460 err->index = lo;
461 err->array = 1;
462 err->type = "userdata";
463 return 0;
464 }
465 lua_pop(L, 1);
466 }
467 }
468 return 1;
469 }
470
tolua_isusertypearray(lua_State * L,int lo,const char * type,int dim,int def,tolua_Error * err)471 TOLUA_API int tolua_isusertypearray(lua_State *L, int lo, const char *type, int dim, int def, tolua_Error *err)
472 {
473 if (!tolua_istable(L, lo, def, err))
474 return 0;
475 else
476 {
477 int i;
478 for (i = 1; i <= dim; ++i)
479 {
480 lua_pushnumber(L, i);
481 lua_gettable(L, lo);
482 if (!(lua_isnil(L, -1) || lua_isuserdata(L, -1)) &&
483 !(def && lua_isnil(L, -1)))
484 {
485 err->index = lo;
486 err->type = type;
487 err->array = 1;
488 return 0;
489 }
490 lua_pop(L, 1);
491 }
492 }
493 return 1;
494 }
495
496 #if 0
497 int tolua_isbooleanfield
498 (lua_State* L, int lo, int i, int def, tolua_Error* err)
499 {
500 lua_pushnumber(L,i);
501 lua_gettable(L,lo);
502 if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) &&
503 !(def && lua_isnil(L,-1))
504 )
505 {
506 err->index = lo;
507 err->array = 1;
508 err->type = "boolean";
509 return 0;
510 }
511 lua_pop(L,1);
512 return 1;
513 }
514
515 int tolua_isnumberfield
516 (lua_State* L, int lo, int i, int def, tolua_Error* err)
517 {
518 lua_pushnumber(L,i);
519 lua_gettable(L,lo);
520 if (!lua_isnumber(L,-1) &&
521 !(def && lua_isnil(L,-1))
522 )
523 {
524 err->index = lo;
525 err->array = 1;
526 err->type = "number";
527 return 0;
528 }
529 lua_pop(L,1);
530 return 1;
531 }
532
533 int tolua_isstringfield
534 (lua_State* L, int lo, int i, int def, tolua_Error* err)
535 {
536 lua_pushnumber(L,i);
537 lua_gettable(L,lo);
538 if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) &&
539 !(def && lua_isnil(L,-1))
540 )
541 {
542 err->index = lo;
543 err->array = 1;
544 err->type = "string";
545 return 0;
546 }
547 lua_pop(L,1);
548 return 1;
549 }
550
551 int tolua_istablefield
552 (lua_State* L, int lo, int i, int def, tolua_Error* err)
553 {
554 lua_pushnumber(L,i+1);
555 lua_gettable(L,lo);
556 if (! lua_istable(L,-1) &&
557 !(def && lua_isnil(L,-1))
558 )
559 {
560 err->index = lo;
561 err->array = 1;
562 err->type = "table";
563 return 0;
564 }
565 lua_pop(L,1);
566 }
567
568 int tolua_isusertablefield
569 (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
570 {
571 lua_pushnumber(L,i);
572 lua_gettable(L,lo);
573 if (! lua_isusertable(L,-1,type) &&
574 !(def && lua_isnil(L,-1))
575 )
576 {
577 err->index = lo;
578 err->array = 1;
579 err->type = type;
580 return 0;
581 }
582 lua_pop(L,1);
583 return 1;
584 }
585
586 int tolua_isuserdatafield
587 (lua_State* L, int lo, int i, int def, tolua_Error* err)
588 {
589 lua_pushnumber(L,i);
590 lua_gettable(L,lo);
591 if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
592 !(def && lua_isnil(L,-1))
593 )
594 {
595 err->index = lo;
596 err->array = 1;
597 err->type = "userdata";
598 return 0;
599 }
600 lua_pop(L,1);
601 return 1;
602 }
603
604 int tolua_isusertypefield
605 (lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
606 {
607 lua_pushnumber(L,i);
608 lua_gettable(L,lo);
609 if (!(lua_isnil(L,-1) || lua_isusertype(L,-1,type)) &&
610 !(def && lua_isnil(L,-1))
611 )
612 {
613 err->index = lo;
614 err->type = type;
615 err->array = 1;
616 return 0;
617 }
618 lua_pop(L,1);
619 return 1;
620 }
621
622 #endif
623