Tizen 2.0 Release
[external/tolua++.git] / tolua_is.c
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. */
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 */
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
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 */
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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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