lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Apparently <me.theuser> yahoo email won't work with this mailing list so I have created this gmail one instead Ive also cleaned up the code a bit to save some bytes and make it a bit easier to follow

I found out it works perfectly well as a lua_register replacement but a bit more testing needs done before I'd declare it a success

lauxlib.c
----------------------------------------------------------------------------------------------------------
static int latebind_func_index(lua_State *L)
{
  const luaL_Reg *llib;
  /* name @ top of stack */
  const char *name = lua_tostring (L, -1);

  luaL_argcheck(L, lua_istable(L, -2) && lua_getmetatable(L, -2), -2,
                "latebind table expected");

  /* lookup late bound func(s), lua_objlen allows check of multiple luaL_Reg */
  for(int i = lua_objlen(L, -1); i > 0; i--) {
    lua_rawgeti (L, -1, i);
    llib = (const luaL_Reg *) lua_touserdata (L, -1);
    lua_pop(L, 1);

    if(!llib)
      continue;

    for (; llib->name; llib++) {
      if(!name || strcmp(name, llib->name) == 0) {
        /* if function is used it is added to the base table */
        lua_pushcclosure(L, llib->func, 0);

        if(!name) /* nil name binds all functions in table immediately */
          lua_setfield (L, -4, llib->name);
        else {
          lua_pushvalue(L, -1); /* dupe closure */
          lua_setfield (L, -5, llib->name);
          /* returns the closure */
          return 1;
        }
      }
    }
  }
  lua_pop(L, 2); /* base table is top of stack */
  return 0;
}

static int latebind_func_pairs(lua_State *L)
{
  luaL_argcheck(L, lua_istable(L, 1), 1, "table expected");
  lua_getglobal(L, "pairs");  /* function to be called / returned */

  lua_createtable(L, 0, 15);
  lua_getmetatable (L, 1);
  lua_setmetatable (L, 3);

  lua_pushnil(L); /*nil name retrieves all late bound functions */
  latebind_func_index(L);

  lua_pushnil(L); /* remove metatable */
  lua_setmetatable (L, 3);

  /* clone base table */
  lua_pushnil(L); /* first key */
  while(lua_next(L, 1) != 0) { 
    lua_pushvalue(L, -2); /* dupe key */
    lua_insert(L, -2); /* Stk = kkv */
    lua_settable(L, 3);
  }

  lua_call(L, 1, 3); /* pairs(t_cloned) */

  return 3;
}

LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
                                const luaL_Reg *l) {
  if(!libname)
  {
    /* if there is no libname register normally */
    luaI_openlib(L, libname, l, 0);
    return;
  }

  /* store this table instead of of the passed luaL_Reg table */
  static const struct luaL_reg late_lib [] =
  {
    {"__latebind", latebind_func_index},
    {NULL, NULL}
  };

  static const struct luaL_reg late_meta [] =
  {
    {"__index", latebind_func_index},
    {"__pairs", latebind_func_pairs},
    {NULL, NULL}
  };

  luaI_openlib(L, libname, late_lib, 0);

  if(!lua_getmetatable(L, -1))
    lua_createtable(L, 5, 2);

  luaI_openlib(L, NULL, late_meta, 0);

  /* address of luaL_Reg is stored in numbered [1] key indices of metatable */

  lua_pushlightuserdata (L, (void *) l);
  lua_rawseti (L, -2, lua_objlen(L, -2) + 1);

  lua_setmetatable(L, -2);
}


lbaselib.c (lua 5.1)
----------------------------------------------------------------------------------------------------------
static int luaB_pairs (lua_State *L) {
  if (!luaL_getmetafield(L, 1, "__pairs")) {  /* no metamethod? */
    luaL_checktype(L, 1, LUA_TTABLE);
    lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */
    lua_pushvalue(L, 1);  /* state, */
    lua_pushnil(L);  /* and initial value */
  }
  else {
    lua_pushvalue(L, 1);  /* argument 'self' to metamethod */
    lua_call(L, 1, 3);  /* get 3 values from metamethod */
  }
  
  return 3;
}