/* 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_getglobal(L, module_name); else lua_pushglobaltable(L); 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 functions */ int luaT_lua_newmetatable(lua_State *L) { const char* tname = luaL_checkstring(L, 1); const void *id; 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(luaT_classmodulename(tname)) lua_getfield(L, LUA_GLOBALSINDEX, luaT_classmodulename(tname)); else lua_pushvalue(L, LUA_GLOBALSINDEX); if(!lua_istable(L, 6)) luaL_error(L, "while creating metatable %s: bad ardument #1 (%s is an invalid module name)", tname, luaT_classmodulename(tname)); /* we first create the new metaclass if we have to */ if(!luaT_typename2id(L, tname)) { /* create the metaclass */ lua_newtable(L); id = lua_topointer(L, -1); /* id = pointer on metaclass */ /* __index points on itself */ lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); /* __typename contains the typename */ lua_pushstring(L, tname); lua_setfield(L, -2, "__typename"); /* by default, __version equals 1 */ lua_pushnumber(L, 1); lua_setfield(L, -2, "__version"); /* register in "*torch.id2tname*" registry table (id -> typename) */ lua_getfield(L, LUA_REGISTRYINDEX, "*torch.id2tname*"); if(lua_isnil(L, -1)) { lua_pop(L, 1); lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "*torch.id2tname*"); lua_getfield(L, LUA_REGISTRYINDEX, "*torch.id2tname*"); } lua_pushlightuserdata(L, (void*)id); lua_pushstring(L, tname); lua_settable(L, -3); lua_pop(L, 1); /* register in "*torch.tname2id*" registry table (typename -> id) */ lua_getfield(L, LUA_REGISTRYINDEX, "*torch.tname2id*"); if(lua_isnil(L, -1)) { lua_pop(L, 1); lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "*torch.tname2id*"); lua_getfield(L, LUA_REGISTRYINDEX, "*torch.tname2id*"); } lua_pushstring(L, tname); lua_pushlightuserdata(L, (void*)id); lua_settable(L, -3); lua_pop(L, 1); } /* we retrieve the existing metaclass */ else { id = luaT_typename2id(L, tname); luaT_pushmetaclass(L, id); } /* 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); luaT_pushmetaclass(L, luaT_typename2id(L, parenttname)); if(lua_isnil(L, -1)) luaL_error(L, "bad argument #2 (invalid parent class name %s)", parenttname); lua_setmetatable(L, -2); } } /******** root-metatable ********/ /* id is the pointer on the metatable registry[id] = root-metatable, so try to see if it exists */ lua_pushlightuserdata(L, (void*)id); /* id */ lua_rawget(L, LUA_REGISTRYINDEX); /* not existing? we create a new one! */ if(lua_isnil(L, -1)) { lua_pop(L, 1); /* remove nil on stack */ lua_newtable(L); /* __index handling */ lua_pushcfunction(L, luaT_rmt__index); lua_setfield(L, -2, "__index"); /* __newindex handling */ lua_pushcfunction(L, luaT_rmt__newindex); lua_setfield(L, -2, "__newindex"); /* __metatable field (point on the metaclass) */ lua_pushvalue(L, -2); lua_setfield(L, -2, "__metatable"); /* __typename contains the typename */ lua_pushstring(L, tname); lua_setfield(L, -2, "__typename"); /* operators handling */ #define MT_ADD_OPERATOR(name) \ lua_pushcfunction(L, luaT_rmt__##name); \ lua_setfield(L, -2, "__" #name) MT_ADD_OPERATOR(tostring); MT_ADD_OPERATOR(add); MT_ADD_OPERATOR(sub); MT_ADD_OPERATOR(mul); MT_ADD_OPERATOR(div); MT_ADD_OPERATOR(mod); MT_ADD_OPERATOR(pow); MT_ADD_OPERATOR(unm); MT_ADD_OPERATOR(concat); MT_ADD_OPERATOR(len); MT_ADD_OPERATOR(eq); MT_ADD_OPERATOR(lt); MT_ADD_OPERATOR(le); MT_ADD_OPERATOR(call); /* assign the metaclass as metatable... */ lua_pushvalue(L, -2); lua_setmetatable(L, -2); /* id is the pointer on the metatable set registry[id] = root-metatable */ lua_pushlightuserdata(L, (void*)id); /* id */ lua_pushvalue(L, -2); /* metatable */ lua_rawset(L, LUA_REGISTRYINDEX); /* registry[id] = metatable */ } /* ok, so now we have the root-metatable on the stack */ /* 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, -4); /* metaclass */ lua_setfield(L, -2, "__index"); /* so we can get the methods */ lua_pushcfunction(L, luaT_cmt__newindex); lua_setfield(L, -2, "__newindex"); /* so we cannot messup */ lua_pushcfunction(L, luaT_cmt__call); lua_setfield(L, -2, "__call"); /* so we can create */ lua_pushvalue(L, -4); lua_setfield(L, -2, "__metatable"); /* redirect to metatable with methods */ lua_setmetatable(L, -2); /* metatable is ... the fancy metatable */ /* set root-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); } else luaL_error(L, "%s has been already assigned a constructor", tname); /* pop constructor metatable */ lua_pop(L, 1); } lua_setfield(L, 6, luaT_classrootname(tname)); /* module.name = constructor-metatable */ lua_pop(L, 1); /* pop the root-metatable */ return 1; /* returns the metaclass */ }