lua-users home
lua-l archive

RE: Userdata Environments

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


Wesley Smith wrote:
> Do you have an URL of this?
> http://lua-users.org/wiki/UserdataEnvironmentExamples turns up an
> empty page. 
> 
> wes
Here is a freshly written complete and tested example, feel free to put
it on the wiki:
/*** module.c *****************************************************/
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#define FOO "foo"
static int lua__foo__do_it(lua_State* L)
{
 printf("it's done in C\n");
 return 0;
}
luaL_Reg foo_methods[] = {
 {"do_it", lua__foo__do_it},
 {0, 0},
};
static int lua__new(lua_State* L)
{
 /* Create a new userdata */
 lua_newuserdata(L, sizeof(int));
 /* Set common metatable to that userdata */
 lua_getfield(L, LUA_REGISTRYINDEX, FOO);
 lua_setmetatable(L, -2);
 /* Set a specific environment table to that userdata */
 lua_newtable(L);
 lua_setfenv(L, -2);
 return 1;
}
luaL_Reg module_functions[] = {
 {"new", lua__new},
 {0, 0},
};
/* __index(self/U, key) */
static int lua__foo___index(lua_State* L)
{
 int U = *(int*)lua_touserdata(L, 1);
 if (lua_isnil(L, 2))
 {
 luaL_typerror(L, 2, "non-nil key");
 }
 /* Retrieve environment variable */
 lua_getfenv(L, 1);
 /* Check if that key points to something in environment */
 lua_pushvalue(L, 2);
 lua_gettable(L, -2);
 if (!lua_isnil(L, -1))
 {
 return 1;
 }
 /* Pop environment and nil */
 lua_pop(L, 2);
 /* Fallback: Retrieve methods in metatable */
 lua_getmetatable(L, 1);
 lua_getfield(L, -1, "methods");
 /* Look for key in methods */
 lua_pushvalue(L, 2);
 lua_gettable(L, -2);
 /* Simply return it, even if its nil */
 return 1;
}
static int lua__foo___newindex(lua_State* L)
{
 int U = *(int*)lua_touserdata(L, 1);
 if (lua_isnil(L, 2))
 {
 luaL_typerror(L, 2, "non-nil key");
 }
 /* Make sure we have a value in slot 3 */
 if (lua_gettop(L)==2)
 lua_pushnil(L);
 /* Retrieve environment variable */
 lua_getfenv(L, 1);
 /* Set the value in the environment table */
 lua_pushvalue(L, 2); /* Push key */
 lua_pushvalue(L, 3); /* Push value */
 lua_settable(L, -3); /* Assign */
 return 0;
}
int luaopen_module(lua_State* L)
{
 /* Create the metatable */
 luaL_newmetatable(L, FOO);
 /* Put userdata methods in metatable.methods */
 lua_newtable(L);
 luaL_register(L, 0, foo_methods);
 lua_setfield(L, -2, "methods");
 /* Set a __index metamethods that accesses environment table and
 * fallback to metatable.methods */
 lua_pushcfunction(L, lua__foo___index);
 lua_setfield(L, -2, "__index");
 /* Set a __newindex metamethods that put everything in the
 * environment */
 lua_pushcfunction(L, lua__foo___newindex);
 lua_setfield(L, -2, "__newindex");
 
 /* Create the module */
 lua_newtable(L);
 luaL_register(L, 0, module_functions);
 return 1;
}
/******************************************************************/
---- test.lua ------------------------------------------------------
local module = require 'module'
local U = module.new()
U:do_it()
U.do_it = function() print("it's done in Lua") end
U:do_it()
--------------------------------------------------------------------
It should output:
it's done in C
it's done in Lua
Feel free to ask for more comments.

AltStyle によって変換されたページ (->オリジナル) /