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