Example #1
0
/* 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 */
}
Example #2
0
/* 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 */
}