#include <stdlib.h>
#include <string.h>
#include "luaT.h"
void* luaT_alloc(lua_State *L, long size)
{
void *ptr;
if(size == 0)
return NULL;
if(size < 0)
luaL_error(L, "$ Torch: invalid memory size -- maybe an overflow?");
ptr = malloc(size);
if(!ptr)
luaL_error(L, "$ Torch: not enough memory: you tried to allocate %dGB. Buy new RAM!", size/1073741824);
return ptr;
}
void* luaT_realloc(lua_State *L, void *ptr, long size)
{
if(!ptr)
return(luaT_alloc(L, size));
if(size == 0)
{
luaT_free(L, ptr);
return NULL;
}
if(size < 0)
luaL_error(L, "$ Torch: invalid memory size -- maybe an overflow?");
ptr = realloc(ptr, size);
if(!ptr)
luaL_error(L, "$ Torch: not enough memory: you tried to reallocate %dGB. Buy new RAM!", size/1073741824);
return ptr;
}
void luaT_free(lua_State *L, void *ptr)
{
free(ptr);
}
void luaT_stackdump(lua_State *L)
{
int i;
const char *tname = NULL;
int top = lua_gettop(L);
for(i = 1; i <= top; i++)
{
int t = lua_type(L, i);
printf("%3d. ", i);
switch(t)
{
case LUA_TSTRING:
printf("'%s'", lua_tostring(L,i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER:
printf("%g", lua_tonumber(L,i));
break;
case LUA_TUSERDATA:
tname = luaT_typename(L, i);
printf("userdata %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
break;
case 10:
tname = luaT_typename(L, i);
printf("cdata %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
break;
case LUA_TTABLE:
lua_pushvalue(L, i);
lua_rawget(L, LUA_REGISTRYINDEX);
if(lua_isstring(L, -1))
tname = lua_tostring(L, -1); /*luaT_typenameid(L, lua_tostring(L, -1)); */
else
tname = NULL;
lua_pop(L, 1);
if(tname)
printf("metatable [%s]", tname);
else
{
tname = luaT_typename(L, i);
printf("table %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
}
break;
default:
printf("Lua object type: %s", lua_typename(L,t));
break;
}
printf("\n");
}
printf("---------------------------------------------\n");
}
/* metatable operator methods */
static int luaT_mt__index(lua_State *L);
static int luaT_mt__newindex(lua_State *L);
static int luaT_mt__tostring(lua_State *L);
static int luaT_mt__add(lua_State *L);
static int luaT_mt__sub(lua_State *L);
static int luaT_mt__mul(lua_State *L);
static int luaT_mt__div(lua_State *L);
static int luaT_mt__mod(lua_State *L);
static int luaT_mt__pow(lua_State *L);
static int luaT_mt__unm(lua_State *L);
static int luaT_mt__concat(lua_State *L);
static int luaT_mt__len(lua_State *L);
static int luaT_mt__eq(lua_State *L);
static int luaT_mt__lt(lua_State *L);
static int luaT_mt__le(lua_State *L);
static int luaT_mt__call(lua_State *L);
/* Constructor-metatable methods */
static int luaT_cmt__call(lua_State *L);
static int luaT_cmt__newindex(lua_State *L);
const char* luaT_newmetatable(lua_State *L, const char *tname, const char *parenttname,
lua_CFunction constructor, lua_CFunction destructor, lua_CFunction factory)
{
lua_pushcfunction(L, luaT_lua_newmetatable);
lua_pushstring(L, tname);
(parenttname ? lua_pushstring(L, parenttname) : lua_pushnil(L));
(constructor ? lua_pushcfunction(L, constructor) : lua_pushnil(L));
(destructor ? lua_pushcfunction(L, destructor) : lua_pushnil(L));
(factory ? lua_pushcfunction(L, factory) : lua_pushnil(L));
lua_call(L, 5, 1);
return luaT_typenameid(L, tname);
}
int luaT_pushmetatable(lua_State *L, const char *tname)
{
lua_getfield(L, LUA_REGISTRYINDEX, tname);
if(lua_isnil(L, -1))
{
lua_pop(L, 1);
return 0;
}
return 1;
}
const char *luaT_typenameid(lua_State *L, const char *tname)
{
if(luaT_pushmetatable(L, tname))
{
const char *tnameid = NULL;
lua_rawget(L, LUA_REGISTRYINDEX);
if(lua_isstring(L, -1))
tnameid = lua_tostring(L, -1);
lua_pop(L, 1); /* the string/nil */
return tnameid;
}
return NULL;
}
static const char cdataname[] = ""
"local _, ffi = pcall(require, 'ffi')\n"
"if ffi then\n"
" local id2name = {}\n"
" return function(cdata, name)\n"
" local id = tonumber(ffi.typeof(cdata))\n"
" if id then\n"
" if name then\n"
" id2name[id] = name\n"
" return name\n"
" else\n"
" return rawget(id2name, id)\n"
" end\n"
" end\n"
" return nil\n"
" end\n"
"else\n"
" return function() end\n"
"end\n";
static const char* luaT_cdataname(lua_State *L, int ud, const char *tname)
{
lua_pushstring(L, "__cdataname");
lua_rawget(L, LUA_REGISTRYINDEX);
if(lua_isnil(L,-1))
{
lua_pop(L, 1);
if(luaL_dostring(L, cdataname)) /* did something go wrong? */
luaL_error(L, "internal error (could not load cdataname): %s", lua_tostring(L, -1));
lua_pushstring(L, "__cdataname");
lua_pushvalue(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
}
if(!lua_isfunction(L, -1)) /* should not happen */
luaL_error(L, "internal error (cdataname is not a function)");
lua_pushvalue(L, ud);
if(tname)
lua_pushstring(L, tname);
if(lua_pcall(L, (tname ? 2 : 1), 1, 0))
luaL_error(L, "internal error (cdataname): %s", lua_tostring(L, -1));
tname = lua_tostring(L, -1);
lua_pop(L, 1);
return tname;
}
const char* luaT_typename(lua_State *L, int ud)
{
if(lua_type(L, ud) == 10)
return luaT_cdataname(L, ud, NULL);
else if(lua_getmetatable(L, ud))
{
const char *tname = NULL;
lua_rawget(L, LUA_REGISTRYINDEX);
if(lua_isstring(L, -1))
tname = lua_tostring(L, -1);
lua_pop(L, 1); /* the string/nil */
return tname;
}
return NULL;
}
void luaT_pushudata(lua_State *L, void *udata, const char *tname)
{
if(udata)
{
void **udata_p = lua_newuserdata(L, sizeof(void*));
*udata_p = udata;
if(!luaT_pushmetatable(L, tname))
luaL_error(L, "Torch internal problem: cannot find metatable for type <%s>", tname);
lua_setmetatable(L, -2);
}
else
lua_pushnil(L);
}
void *luaT_toudata(lua_State *L, int ud, const char *tname)
{
void **p = lua_touserdata(L, ud);
if(p != NULL) /* value is a userdata? */
{
if(!luaT_pushmetatable(L, tname))
luaL_error(L, "Torch internal problem: cannot find metatable for type <%s>", tname);
/* initialize the table we want to get the metatable on */
/* note that we have to be careful with indices, as we just inserted stuff */
lua_pushvalue(L, (ud < 0 ? ud - 1 : ud));
while(lua_getmetatable(L, -1)) /* get the next metatable */
{
lua_remove(L, -2); /* remove the previous metatable [or object, if first time] */
if(lua_rawequal(L, -1, -2))
{
lua_pop(L, 2); /* remove the two metatables */
return *p;
}
}
lua_pop(L, 2); /* remove the two metatables */
}
return NULL;
}
int luaT_isudata(lua_State *L, int ud, const char *tname)
{
if(luaT_toudata(L, ud, tname))
return 1;
else
return 0;
}
void *luaT_checkudata(lua_State *L, int ud, const char *tname)
{
void *p = luaT_toudata(L, ud, tname);
if(!p)
luaT_typerror(L, ud, tname);
return p;
}
void *luaT_getfieldcheckudata(lua_State *L, int ud, const char *field, const char *tname)
{
void *p;
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
p = luaT_toudata(L, -1, tname);
if(!p)
luaL_error(L, "bad argument #%d (field %s is not a %s)", ud, field, tname);
return p;
}
void *luaT_getfieldchecklightudata(lua_State *L, int ud, const char *field)
{
void *p;
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_islightuserdata(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a light userdata)", ud, field);
p = lua_touserdata(L, -1);
return p;
}
double luaT_getfieldchecknumber(lua_State *L, int ud, const char *field)
{
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_isnumber(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a number)", ud, field);
return lua_tonumber(L, -1);
}
int luaT_getfieldcheckint(lua_State *L, int ud, const char *field)
{
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_isnumber(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a number)", ud, field);
return (int)lua_tonumber(L, -1);
}
const char* luaT_getfieldcheckstring(lua_State *L, int ud, const char *field)
{
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_isstring(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a string)", ud, field);
return lua_tostring(L, -1);
}
int luaT_getfieldcheckboolean(lua_State *L, int ud, const char *field)
{
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_isboolean(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a boolean)", ud, field);
return lua_toboolean(L, -1);
}
void luaT_getfieldchecktable(lua_State *L, int ud, const char *field)
{
lua_getfield(L, ud, field);
if(lua_isnil(L, -1))
luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
if(!lua_istable(L, -1))
luaL_error(L, "bad argument #%d (field %s is not a table)", ud, field);
}
/**** type checks as in luaL ****/
int luaT_typerror(lua_State *L, int ud, const char *tname)
{
const char *msg;
const char *tnameud = luaT_typename(L, ud);
if(!tnameud)
tnameud = lua_typename(L, ud);
msg = lua_pushfstring(L, "%s expected, got %s",
tname,
(tnameud ? tnameud : "unknown object"));
return luaL_argerror(L, ud, msg);
}
int luaT_checkboolean(lua_State *L, int ud)
{
if(!lua_isboolean(L, ud))
luaT_typerror(L, ud, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, ud);
}
int luaT_optboolean(lua_State *L, int ud, int def)
{
if(lua_isnoneornil(L,ud))
return def;
return luaT_checkboolean(L, ud);
}
void luaT_registeratname(lua_State *L, const struct luaL_Reg *methods, const char *name)
{
int idx = lua_gettop(L);
luaL_checktype(L, idx, LUA_TTABLE);
lua_pushstring(L, name);
lua_rawget(L, idx);
if(lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_pushstring(L, name);
lua_newtable(L);
lua_rawset(L, idx);
lua_pushstring(L, name);
lua_rawget(L, idx);
}
luaL_register(L, NULL, methods);
lua_pop(L, 1);
}
/* utility functions */
const char *luaT_classrootname(const char *tname)
{
int i;
int sz = strlen(tname);
for(i = 0; i < sz; i++)
{
if(tname[i] == '.')
return tname+i+1;
}
return tname;
}
/* module_name must be a buffer at least as big as tname
* return true if the class is part of a module */
int luaT_classmodulename(const char *tname, char *module_name)
{
char chars[] = {'.', '\0'};
size_t n;
n = strcspn(tname, chars);
strncpy(module_name, tname, n);
module_name[n] = '\0';
return tname[n] == '.';
}
/* Lua only functions */
int luaT_lua_newmetatable(lua_State *L)
{
const char* tname = luaL_checkstring(L, 1);
char module_name[256];
int is_in_module = 0;
is_in_module = luaT_classmodulename(tname, module_name);
lua_settop(L, 5);
luaL_argcheck(L, lua_isnoneornil(L, 2) || lua_isstring(L, 2), 2, "parent class name or nil expected");
luaL_argcheck(L, lua_isnoneornil(L, 3) || lua_isfunction(L, 3), 3, "constructor function or nil expected");
luaL_argcheck(L, lua_isnoneornil(L, 4) || lua_isfunction(L, 4), 4, "destructor function or nil expected");
luaL_argcheck(L, lua_isnoneornil(L, 5) || lua_isfunction(L, 5), 5, "factory function or nil expected");
if(is_in_module)
lua_getfield(L, LUA_GLOBALSINDEX, module_name);
else
lua_pushvalue(L, LUA_GLOBALSINDEX);
if(!lua_istable(L, 6))
luaL_error(L, "while creating metatable %s: bad argument #1 (%s is an invalid module name)", tname, module_name);
/* we first create the new metaclass if we have to */
if(!luaT_pushmetatable(L, tname))
{
/* create the metatable */
lua_newtable(L);
/* registry[name] = metatable */
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, tname);
/* registry[metatable] = tname */
lua_pushvalue(L, -1);
lua_pushstring(L, tname);
lua_rawset(L, LUA_REGISTRYINDEX);
/* __index handling */
lua_pushcfunction(L, luaT_mt__index);
lua_setfield(L, -2, "__index");
/* __newindex handling */
lua_pushcfunction(L, luaT_mt__newindex);
lua_setfield(L, -2, "__newindex");
/* __typename contains the typename */
lua_pushstring(L, tname);
lua_setfield(L, -2, "__typename");
/* __metatable is self */
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__metatable");
/* by default, __version equals 1 */
lua_pushnumber(L, 1);
lua_setfield(L, -2, "__version");
/* assign default operator functions */
lua_pushcfunction(L, luaT_mt__tostring);
lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, luaT_mt__add);
lua_setfield(L, -2, "__add");
lua_pushcfunction(L, luaT_mt__sub);
lua_setfield(L, -2, "__sub");
lua_pushcfunction(L, luaT_mt__mul);
lua_setfield(L, -2, "__mul");
lua_pushcfunction(L, luaT_mt__div);
lua_setfield(L, -2, "__div");
lua_pushcfunction(L, luaT_mt__mod);
lua_setfield(L, -2, "__mod");
lua_pushcfunction(L, luaT_mt__pow);
lua_setfield(L, -2, "__pow");
lua_pushcfunction(L, luaT_mt__unm);
lua_setfield(L, -2, "__unm");
lua_pushcfunction(L, luaT_mt__concat);
lua_setfield(L, -2, "__concat");
lua_pushcfunction(L, luaT_mt__len);
lua_setfield(L, -2, "__len");
lua_pushcfunction(L, luaT_mt__eq);
lua_setfield(L, -2, "__eq");
lua_pushcfunction(L, luaT_mt__lt);
lua_setfield(L, -2, "__lt");
lua_pushcfunction(L, luaT_mt__le);
lua_setfield(L, -2, "__le");
lua_pushcfunction(L, luaT_mt__call);
lua_setfield(L, -2, "__call");
}
/* we assign the parent class if necessary */
if(!lua_isnoneornil(L, 2))
{
if(lua_getmetatable(L, -1))
luaL_error(L, "class %s has been already assigned a parent class\n", tname);
else
{
const char* parenttname = luaL_checkstring(L, 2);
if(!luaT_pushmetatable(L, parenttname))
luaL_error(L, "bad argument #2 (invalid parent class name %s)", parenttname);
lua_setmetatable(L, -2);
}
}
/* register the destructor function */
if(!lua_isnoneornil(L, 4))
{
/* does it exists already? */
lua_pushstring(L, "__gc");
lua_rawget(L, -2);
if(lua_isnil(L, -1))
{
lua_pop(L, 1); /* pop nil */
lua_pushstring(L, "__gc");
lua_pushvalue(L, 4);
lua_rawset(L, -3);
}
else
luaL_error(L, "%s has been already assigned a destructor", tname);
}
/* register the factory function */
if(!lua_isnoneornil(L, 5))
{
/* does it exists already? */
lua_pushstring(L, "__factory");
lua_rawget(L, -2);
if(lua_isnil(L, -1))
{
lua_pop(L, 1); /* pop nil */
lua_pushstring(L, "__factory");
lua_pushvalue(L, 5);
lua_rawset(L, -3);
}
else
luaL_error(L, "%s has been already assigned a factory", tname);
}
/******** Constructor table and metatable ********/
lua_pushstring(L, "__constructor");
lua_rawget(L, -2);
if(lua_isnil(L, -1))
{
lua_pop(L, 1); /* pop nil */
lua_newtable(L); /* fancy table */
lua_newtable(L); /* fancy metatable */
lua_pushvalue(L, -3); /* metatable */
lua_setfield(L, -2, "__index"); /* so we can get the methods */
lua_pushcfunction(L, luaT_cmt__newindex);
lua_setfield(L, -2, "__newindex"); /* so we add new methods */
lua_pushcfunction(L, luaT_cmt__call);
lua_setfield(L, -2, "__call"); /* so we can create, we are here for only that */
lua_pushvalue(L, -3);
lua_setfield(L, -2, "__metatable"); /* redirect to metatable with methods */
lua_setmetatable(L, -2); /* constructor metatable is ... this fancy metatable */
/* set metatable[__constructor] = constructor-metatable */
lua_pushstring(L, "__constructor");
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
/* register the constructor function */
if(!lua_isnoneornil(L, 3))
{
/* get constructor metatable */
lua_getmetatable(L, -1);
/* does it exists already? */
lua_pushstring(L, "__new");
lua_rawget(L, -2);
if(lua_isnil(L, -1))
{
lua_pop(L, 1); /* pop nil */
lua_pushstring(L, "__new");
lua_pushvalue(L, 3);
lua_rawset(L, -3);
/* set "new" in the metatable too */
lua_pushstring(L, "new");
lua_pushvalue(L, 3);
lua_rawset(L, -5);
}
else
luaL_error(L, "%s has been already assigned a constructor", tname);
/* pop constructor metatable */
lua_pop(L, 1);
}
/* module.name = constructor metatable */
lua_setfield(L, 6, luaT_classrootname(tname));
return 1; /* returns the metatable */
}
/* Lua only utility functions */
/* add any custom type, provided the object has a metatable */
int luaT_lua_metatype(lua_State *L)
{
if( (lua_gettop(L) != 2) && (lua_gettop(L) != 3) )
luaL_error(L, "expecting: string table [ctype]");
luaL_checkstring(L, 1);
luaL_checktype(L, 2, LUA_TTABLE);
if(lua_gettop(L) == 3)
{
if(!luaT_cdataname(L, 3, lua_tostring(L, 1)))
luaL_error(L, "could not register cdata type -- missing ffi library?");
}
/* registry[name] = metatable */
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_rawset(L, LUA_REGISTRYINDEX);
/* registry[metatable] = tname */
lua_pushvalue(L, 2);
lua_pushvalue(L, 1);
lua_rawset(L, LUA_REGISTRYINDEX);
return 0;
}
/* return a userdata from a C pointer */
/* you are better to know what you are doing */
int luaT_lua_pushudata(lua_State *L)
{
void *udata = NULL;
const char *tname = luaL_checkstring(L, 2);
if(lua_type(L, 1) == 10)
udata = *((void**)lua_topointer(L, 1));
else if(lua_isnumber(L, 1))
udata = (void*)(long)lua_tonumber(L, 1);
else
luaL_argerror(L, 1, "expecting number or cdata");
luaT_pushudata(L, udata, tname);
return 1;
}
int luaT_lua_factory(lua_State *L)
{
const char* tname = luaL_checkstring(L, 1);
if(luaT_pushmetatable(L, tname) && !lua_isnil(L, -1))
{
lua_pushstring(L, "__factory");
lua_rawget(L, -2);
}
else
{
lua_pushnil(L);
}
return 1;
}
int luaT_lua_getconstructortable(lua_State *L)
{
const char* tname = luaL_checkstring(L, 1);
if(luaT_pushmetatable(L, tname))
{
lua_pushstring(L, "__constructor");
lua_rawget(L, -2);
return 1;
}
return 0;
}
int luaT_lua_typename(lua_State *L)
{
const char* tname = NULL;
luaL_checkany(L, 1);
if((tname = luaT_typename(L, 1)))
{
lua_pushstring(L, tname);
return 1;
}
return 0;
}
int luaT_lua_isequal(lua_State *L)
{
if(lua_isuserdata(L, 1) && lua_isuserdata(L, 2))
{
void **u1, **u2;
luaL_argcheck(L, luaT_typename(L, 1), 1, "Torch object expected");
luaL_argcheck(L, luaT_typename(L, 2), 2, "Torch object expected");
u1 = lua_touserdata(L, 1);
u2 = lua_touserdata(L, 2);
if(*u1 == *u2)
lua_pushboolean(L, 1);
else
lua_pushboolean(L, 0);
}
else if(lua_istable(L, 1) && lua_istable(L, 2))
lua_pushboolean(L, lua_rawequal(L, 1, 2));
else
lua_pushboolean(L, 0);
return 1;
}
int luaT_lua_pointer(lua_State *L)
{
if(lua_isuserdata(L, 1))
{
void **ptr;
luaL_argcheck(L, luaT_typename(L, 1), 1, "Torch object expected");
ptr = lua_touserdata(L, 1);
lua_pushnumber(L, (long)(*ptr));
return 1;
}
else if(lua_istable(L, 1) || lua_isthread(L, 1) || lua_isfunction(L, 1))
{
const void* ptr = lua_topointer(L, 1);
lua_pushnumber(L, (long)(ptr));
return 1;
}
else if(lua_type(L, 1) == 10) /* cdata */
{
/* we want the pointer holded by cdata */
/* not the pointer on the cdata object */
const void* ptr = *((void**)lua_topointer(L, 1));
lua_pushnumber(L, (long)(ptr));
return 1;
}
else if(lua_isstring(L, 1))
{
const char* ptr = lua_tostring(L, 1);
lua_pushnumber(L, (long)(ptr));
return 1;
}
else
luaL_error(L, "Torch object, table, thread, cdata or function expected");
return 0;
}
int luaT_lua_setenv(lua_State *L)
{
if(!lua_isfunction(L, 1) && !lua_isuserdata(L, 1))
luaL_typerror(L, 1, "function or userdata");
luaL_checktype(L, 2, LUA_TTABLE);
lua_setfenv(L, 1);
return 0;
}
int luaT_lua_getenv(lua_State *L)
{
if(!lua_isfunction(L, 1) && !lua_isuserdata(L, 1))
luaL_typerror(L, 1, "function or userdata");
lua_getfenv(L, 1);
return 1;
}
int luaT_lua_getmetatable(lua_State *L)
{
const char *tname = luaL_checkstring(L, 1);
if(luaT_pushmetatable(L, tname))
return 1;
return 0;
}
int luaT_lua_version(lua_State *L)
{
luaL_checkany(L, 1);
if(lua_type(L, 1) == 10)
{
const char *tname = luaT_cdataname(L, 1, NULL);
if(tname)
{
luaT_pushmetatable(L, tname);
lua_pushstring(L, "__version");
lua_rawget(L, -2);
return 1;
}
return 0;
}
else if(lua_getmetatable(L, 1))
{
lua_pushstring(L, "__version");
lua_rawget(L, -2);
return 1;
}
return 0;
}
int luaT_lua_setmetatable(lua_State *L)
{
const char *tname = luaL_checkstring(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
if(!luaT_pushmetatable(L, tname))
luaL_error(L, "unknown typename %s\n", tname);
lua_setmetatable(L, 1);
return 1;
}
/* metatable operator methods */
static int luaT_mt__index(lua_State *L)
{
if(!lua_getmetatable(L, 1))
luaL_error(L, "critical internal indexing error: no metatable found");
if(!lua_istable(L, -1))
luaL_error(L, "critical internal indexing error: not a metatable");
/* test for __index__ method first */
lua_getfield(L, -1, "__index__");
if(!lua_isnil(L, -1))
{
int result;
if(!lua_isfunction(L, -1))
luaL_error(L, "critical internal indexing error: __index__ is not a function");
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_call(L, 2, LUA_MULTRET); /* DEBUG: risque: faut vraiment retourner 1 ou 2 valeurs... */
result = lua_toboolean(L, -1);
lua_pop(L, 1);
if(result)
return 1;
/* on the stack: 1. the object 2. the value 3. the metatable */
/* apparently, __index wants only one element returned */
/* return lua_gettop(L)-3; */
}
else
lua_pop(L, 1); /* remove nil __index__ on the stack */
lua_pushvalue(L, 2);
lua_gettable(L, -2);
return 1;
}
static int luaT_mt__newindex(lua_State *L)
{
if(!lua_getmetatable(L, 1))
luaL_error(L, "critical internal indexing error: no metatable found");
if(!lua_istable(L, -1))
luaL_error(L, "critical internal indexing error: not a metatable");
/* test for __newindex__ method first */
lua_getfield(L, -1, "__newindex__");
if(!lua_isnil(L, -1))
{
int result;
if(!lua_isfunction(L, -1))
luaL_error(L, "critical internal indexing error: __newindex__ is not a function");
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_call(L, 3, 1); /* DEBUG: risque: faut vraiment retourner qqch */
result = lua_toboolean(L, -1);
lua_pop(L, 1);
if(result)
return 0;
}
else
lua_pop(L, 1); /* remove nil __newindex__ on the stack */
lua_pop(L, 1); /* pop the metatable */
if(lua_istable(L, 1))
lua_rawset(L, 1);
else
luaL_error(L, "the class %s cannot be indexed", luaT_typename(L, 1));
return 0;
}
/* note: check dans metatable pour ca, donc necessaire */
#define MT_DECLARE_OPERATOR(NAME, NIL_BEHAVIOR) \
int luaT_mt__##NAME(lua_State *L) \
{ \
if(!lua_getmetatable(L, 1)) \
luaL_error(L, "internal error in __" #NAME ": no metatable"); \
\
lua_getfield(L, -1, "__" #NAME "__"); \
if(lua_isnil(L, -1)) \
{ \
NIL_BEHAVIOR; \
} \
else \
{ \
if(lua_isfunction(L, -1)) \
{ \
lua_insert(L, 1); /* insert function */ \
lua_pop(L, 1); /* remove metatable */ \
lua_call(L, lua_gettop(L)-1, LUA_MULTRET); /* we return the result of the call */ \
return lua_gettop(L); \
} \
/* we return the thing the user left in __tostring__ */ \
} \
return 0; \
}
MT_DECLARE_OPERATOR(tostring,
lua_pushstring(L, luaT_typename(L, 1));
return 1;)
MT_DECLARE_OPERATOR(add, luaL_error(L, "%s has no addition operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(sub, luaL_error(L, "%s has no substraction operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(mul, luaL_error(L, "%s has no multiplication operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(div, luaL_error(L, "%s has no division operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(mod, luaL_error(L, "%s has no modulo operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(pow, luaL_error(L, "%s has no power operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(unm, luaL_error(L, "%s has no negation operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(concat, luaL_error(L, "%s has no concat operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(len, luaL_error(L, "%s has no length operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(eq,
lua_settop(L, 2);
lua_pushcfunction(L, luaT_lua_isequal);
lua_insert(L, 1);
lua_call(L, 2, 1);
return 1;)
MT_DECLARE_OPERATOR(lt, luaL_error(L, "%s has no lower than operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(le, luaL_error(L, "%s has no lower or equal than operator", luaT_typename(L, 1)))
MT_DECLARE_OPERATOR(call, luaL_error(L, "%s has no call operator", luaT_typename(L, 1)))
/* constructor metatable methods */
int luaT_cmt__call(lua_State *L)
{
if(!lua_istable(L, 1))
luaL_error(L, "internal error in __call: not a constructor table");
if(!lua_getmetatable(L, 1))
luaL_error(L, "internal error in __call: no metatable available");
lua_pushstring(L, "__new");
lua_rawget(L, -2);
if(lua_isnil(L, -1))
luaL_error(L, "no constructor available");
lua_remove(L, 1); /* remove constructor atable */
lua_insert(L, 1); /* insert constructor */
lua_pop(L, 1); /* remove fancy metatable */
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
return lua_gettop(L);
}
int luaT_cmt__newindex(lua_State *L)
{
if(!lua_istable(L, 1))
luaL_error(L, "internal error in __newindex: not a constructor table");
if(!lua_getmetatable(L, 1))
luaL_error(L, "internal error in __newindex: no metatable available");
lua_pushstring(L, "__metatable");
lua_rawget(L, -2);
if(!lua_istable(L, -1))
luaL_error(L, "internal error in __newindex: no metaclass available");
lua_insert(L, 2);
lua_pop(L, 1); /* remove the metatable over the constructor table */
lua_rawset(L, -3);
return 0;
}
/******************** deprecated functions ********************/
int luaT_pushmetaclass(lua_State *L, const char *tname)
{
return luaT_pushmetatable(L, tname);
}
const char* luaT_id(lua_State *L, int ud)
{
return luaT_typename(L, ud);
}
const char* luaT_id2typename(lua_State *L, const char *id)
{
return id;
}
const char* luaT_typename2id(lua_State *L, const char *tname)
{
return luaT_typenameid(L, tname);
}
int luaT_getmetaclass(lua_State *L, int index)
{
return lua_getmetatable(L, index);
}
const char* luaT_checktypename2id(lua_State *L, const char *tname)
{
const char* id = luaT_typenameid(L, tname);
if(!id)
luaL_error(L, "unknown class <%s>", tname);
return id;
}
void luaT_registeratid(lua_State *L, const struct luaL_Reg *methods, const char *id)
{
luaT_registeratname(L, methods, id);
}
/**************************************************************/