621 lines
12 KiB
C
621 lines
12 KiB
C
/* tolua: functions to check types.
|
|
** Support code for Lua bindings.
|
|
** Written by Waldemar Celes
|
|
** TeCGraf/PUC-Rio
|
|
** Apr 2003
|
|
** $Id: $
|
|
*/
|
|
|
|
/* This code is free software; you can redistribute it and/or modify it.
|
|
** The software provided hereunder is on an "as is" basis, and
|
|
** the author has no obligation to provide maintenance, support, updates,
|
|
** enhancements, or modifications.
|
|
*/
|
|
|
|
#include "tolua++.h"
|
|
#include "lauxlib.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* a fast check if a is b, without parameter validation
|
|
i.e. if b is equal to a or a superclass of a. */
|
|
TOLUA_API int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index)
|
|
{
|
|
int result;
|
|
if (lua_rawequal(L,mt_indexa,mt_indexb))
|
|
result = 1;
|
|
else
|
|
{
|
|
if (super_index) {
|
|
lua_pushvalue(L, super_index);
|
|
} else {
|
|
lua_pushliteral(L,"tolua_super");
|
|
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */
|
|
};
|
|
lua_pushvalue(L,mt_indexa); /* stack: super mta */
|
|
lua_rawget(L,-2); /* stack: super super[mta] */
|
|
lua_pushvalue(L,mt_indexb); /* stack: super super[mta] mtb */
|
|
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super super[mta] typenameB */
|
|
lua_rawget(L,-2); /* stack: super super[mta] bool */
|
|
result = lua_toboolean(L,-1);
|
|
lua_pop(L,3);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* Push and returns the corresponding object typename */
|
|
TOLUA_API const char* tolua_typename (lua_State* L, int lo)
|
|
{
|
|
int tag = lua_type(L,lo);
|
|
if (tag == LUA_TNONE)
|
|
lua_pushstring(L,"[no object]");
|
|
else if (tag != LUA_TUSERDATA && tag != LUA_TTABLE)
|
|
lua_pushstring(L,lua_typename(L,tag));
|
|
else if (tag == LUA_TUSERDATA)
|
|
{
|
|
if (!lua_getmetatable(L,lo))
|
|
lua_pushstring(L,lua_typename(L,tag));
|
|
else
|
|
{
|
|
lua_rawget(L,LUA_REGISTRYINDEX);
|
|
if (!lua_isstring(L,-1))
|
|
{
|
|
lua_pop(L,1);
|
|
lua_pushstring(L,"[undefined]");
|
|
}
|
|
}
|
|
}
|
|
else /* is table */
|
|
{
|
|
lua_pushvalue(L,lo);
|
|
lua_rawget(L,LUA_REGISTRYINDEX);
|
|
if (!lua_isstring(L,-1))
|
|
{
|
|
lua_pop(L,1);
|
|
lua_pushstring(L,"table");
|
|
}
|
|
else
|
|
{
|
|
lua_pushstring(L,"class ");
|
|
lua_insert(L,-2);
|
|
lua_concat(L,2);
|
|
}
|
|
}
|
|
return lua_tostring(L,-1);
|
|
}
|
|
|
|
TOLUA_API void tolua_error (lua_State* L, const char* msg, tolua_Error* err)
|
|
{
|
|
if (msg[0] == '#')
|
|
{
|
|
const char* expected = err->type;
|
|
const char* provided = tolua_typename(L,err->index);
|
|
if (msg[1]=='f')
|
|
{
|
|
int narg = err->index;
|
|
if (err->array)
|
|
luaL_error(L,"%s\n argument #%d is array of '%s'; array of '%s' expected.\n",
|
|
msg+2,narg,provided,expected);
|
|
else
|
|
luaL_error(L,"%s\n argument #%d is '%s'; '%s' expected.\n",
|
|
msg+2,narg,provided,expected);
|
|
}
|
|
else if (msg[1]=='v')
|
|
{
|
|
if (err->array)
|
|
luaL_error(L,"%s\n value is array of '%s'; array of '%s' expected.\n",
|
|
msg+2,provided,expected);
|
|
else
|
|
luaL_error(L,"%s\n value is '%s'; '%s' expected.\n",
|
|
msg+2,provided,expected);
|
|
}
|
|
}
|
|
else
|
|
luaL_error(L,msg);
|
|
}
|
|
|
|
/* the equivalent of lua_is* for usertable */
|
|
static int lua_isusertable (lua_State* L, int lo, const const char* type)
|
|
{
|
|
int r = 0;
|
|
if (lo < 0) lo = lua_gettop(L)+lo+1;
|
|
lua_pushvalue(L,lo);
|
|
lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[t] */
|
|
if (lua_isstring(L,-1))
|
|
{
|
|
r = strcmp(lua_tostring(L,-1),type)==0;
|
|
if (!r)
|
|
{
|
|
/* try const */
|
|
lua_pushstring(L,"const ");
|
|
lua_insert(L,-2);
|
|
lua_concat(L,2);
|
|
r = lua_isstring(L,-1) && strcmp(lua_tostring(L,-1),type)==0;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
return r;
|
|
}
|
|
|
|
int push_table_instance(lua_State* L, int lo) {
|
|
|
|
if (lua_istable(L, lo)) {
|
|
|
|
lua_pushstring(L, ".c_instance");
|
|
lua_gettable(L, lo);
|
|
if (lua_isuserdata(L, -1)) {
|
|
|
|
lua_replace(L, lo);
|
|
return 1;
|
|
} else {
|
|
|
|
lua_pop(L, 1);
|
|
return 0;
|
|
};
|
|
} else {
|
|
return 0;
|
|
};
|
|
|
|
return 0;
|
|
};
|
|
|
|
/* the equivalent of lua_is* for usertype */
|
|
static int lua_isusertype (lua_State* L, int lo, const char* type)
|
|
{
|
|
if (!lua_isuserdata(L,lo)) {
|
|
if (!push_table_instance(L, lo)) {
|
|
return 0;
|
|
};
|
|
};
|
|
{
|
|
/* check if it is of the same type */
|
|
int r;
|
|
const char *tn;
|
|
if (lua_getmetatable(L,lo)) /* if metatable? */
|
|
{
|
|
lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[mt] */
|
|
tn = lua_tostring(L,-1);
|
|
r = tn && (strcmp(tn,type) == 0);
|
|
lua_pop(L, 1);
|
|
if (r)
|
|
return 1;
|
|
else
|
|
{
|
|
/* check if it is a specialized class */
|
|
lua_pushstring(L,"tolua_super");
|
|
lua_rawget(L,LUA_REGISTRYINDEX); /* get super */
|
|
lua_getmetatable(L,lo);
|
|
lua_rawget(L,-2); /* get super[mt] */
|
|
if (lua_istable(L,-1))
|
|
{
|
|
int b;
|
|
lua_pushstring(L,type);
|
|
lua_rawget(L,-2); /* get super[mt][type] */
|
|
b = lua_toboolean(L,-1);
|
|
lua_pop(L,3);
|
|
if (b)
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isnoobj (lua_State* L, int lo, tolua_Error* err)
|
|
{
|
|
if (lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "[no object]";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isboolean (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isnil(L,lo) || lua_isboolean(L,lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "boolean";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isnumber (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isnumber(L,lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "number";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isstring (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isnil(L,lo) || lua_isstring(L,lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "string";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_istable (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_istable(L,lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "table";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isusertable (lua_State* L, int lo, const char* type, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isusertable(L,lo,type))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = type;
|
|
return 0;
|
|
}
|
|
|
|
|
|
TOLUA_API int tolua_isuserdata (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isnil(L,lo) || lua_isuserdata(L,lo))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "userdata";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isvaluenil (lua_State* L, int lo, tolua_Error* err) {
|
|
|
|
if (lua_gettop(L)<abs(lo))
|
|
return 0; /* somebody else should chack this */
|
|
if (!lua_isnil(L, lo))
|
|
return 0;
|
|
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "value";
|
|
return 1;
|
|
};
|
|
|
|
TOLUA_API int tolua_isvalue (lua_State* L, int lo, int def, tolua_Error* err)
|
|
{
|
|
if (def || abs(lo)<=lua_gettop(L)) /* any valid index */
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = "value";
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err)
|
|
{
|
|
if (def && lua_gettop(L)<abs(lo))
|
|
return 1;
|
|
if (lua_isnil(L,lo) || lua_isusertype(L,lo,type))
|
|
return 1;
|
|
err->index = lo;
|
|
err->array = 0;
|
|
err->type = type;
|
|
return 0;
|
|
}
|
|
|
|
TOLUA_API int tolua_isvaluearray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_isbooleanarray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "boolean";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_isnumberarray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!lua_isnumber(L,-1) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "number";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_isstringarray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "string";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_istablearray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (! lua_istable(L,-1) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "table";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_isuserdataarray
|
|
(lua_State* L, int lo, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "userdata";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
TOLUA_API int tolua_isusertypearray
|
|
(lua_State* L, int lo, const char* type, int dim, int def, tolua_Error* err)
|
|
{
|
|
if (!tolua_istable(L,lo,def,err))
|
|
return 0;
|
|
else
|
|
{
|
|
int i;
|
|
for (i=1; i<=dim; ++i)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->type = type;
|
|
err->array = 1;
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if 0
|
|
int tolua_isbooleanfield
|
|
(lua_State* L, int lo, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isboolean(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "boolean";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
int tolua_isnumberfield
|
|
(lua_State* L, int lo, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!lua_isnumber(L,-1) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "number";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
int tolua_isstringfield
|
|
(lua_State* L, int lo, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isstring(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "string";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
int tolua_istablefield
|
|
(lua_State* L, int lo, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i+1);
|
|
lua_gettable(L,lo);
|
|
if (! lua_istable(L,-1) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "table";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
}
|
|
|
|
int tolua_isusertablefield
|
|
(lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (! lua_isusertable(L,-1,type) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = type;
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
int tolua_isuserdatafield
|
|
(lua_State* L, int lo, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->array = 1;
|
|
err->type = "userdata";
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
int tolua_isusertypefield
|
|
(lua_State* L, int lo, const char* type, int i, int def, tolua_Error* err)
|
|
{
|
|
lua_pushnumber(L,i);
|
|
lua_gettable(L,lo);
|
|
if (!(lua_isnil(L,-1) || lua_isusertype(L,-1,type)) &&
|
|
!(def && lua_isnil(L,-1))
|
|
)
|
|
{
|
|
err->index = lo;
|
|
err->type = type;
|
|
err->array = 1;
|
|
return 0;
|
|
}
|
|
lua_pop(L,1);
|
|
return 1;
|
|
}
|
|
|
|
#endif
|