lua-users home
lua-l archive

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


Wow!!!, thank you for the explanation now I have a new understanding about lua stack and its environments. Definitely the purpose of pseudo-indices is not very clear in the manual. I thought that objects at pseudo-indices were special objects that can be accessed but can not be changed because they are not really in the current stack. I was completely wrong.

That means , for example, a function can change the global thread environment or even the registry with lua_replace(L, LUA_GLOBALSINDEX, ) or lua_replace(L, LUA_REGISTRYINDEX, ) , isn't it? Now I think about it, it seems quite reasonable.

Jose L.

PD: And please excuse my bad English :)

El 29/08/2006, a las 18:29, Luis Carvalho escribió:

On Tue, Aug 29, 2006 at 08:57:22AM +0200, Jose Luis Hidalgo Valiño wrote:
<snip>
LUA_ENVIRONINDEX seems a way to hold data locally to a set of
functions ( or only one ) but without loosing the possibility of
access the full global environment (the thread environment) through
LUA_GLOBALSINDEX.

I like to think of LUA_ENVIRONINDEX as a sort of "lua_upvalueindex (0)": it is like a shared upvalue among all C functions that have the same environment. If by locally you mean private, then a closure is more appropriate, as Mildred
stated. Check toy example below.

In lua 5.1 lua_setfenv "changes" the behavior of LUA_ENVIRONINDEX or
LUA_GLOBALSINDEX ? I'm not sure.

I don't understand what you mean, but since lua_setfenv changes the
environment of a function, thread or userdata, it affects LUA_ENVIRONINDEX for
C functions.

A simple example:

/* environ.c */
#include <lua.h>
#include <lauxlib.h>

static int environ_upv (lua_State *L) {
  lua_Number e, u;
  /* get environment data */
  lua_rawgeti(L, LUA_ENVIRONINDEX, 1);
  e = luaL_optnumber(L, -1, 0);
  /* update environment */
  lua_pushnumber(L, e+1);
  lua_rawseti(L, LUA_ENVIRONINDEX, 1);
  /* get closure data */
  u = luaL_optnumber(L, lua_upvalueindex(1), 0);
  /* update closure */
  lua_pushnumber(L, u+1);
  lua_replace(L, lua_upvalueindex(1));
  lua_pushnumber(L, e);
  lua_pushnumber(L, u);
  return 2;
}

int luaopen_environ (lua_State *L) {
  /* set current environment */
  lua_createtable(L, 1, 0); /* environ table */
  lua_pushnumber(L, 0);
  lua_rawseti(L, -2, 1); /* environ[1] = 0 */
  lua_replace(L, LUA_ENVIRONINDEX);
  /* push closures with default environment (above) */
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_setfield(L, LUA_GLOBALSINDEX, "env1");
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_setfield(L, LUA_GLOBALSINDEX, "env2");
  /* change environment using setfenv */
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_createtable(L, 1, 0); /* new environ table */
  lua_pushnumber(L, 0);
  lua_rawseti(L, -2, 1); /* environ[1] = 0 */
  lua_setfenv(L, -2);
  lua_setfield(L, LUA_GLOBALSINDEX, "env3");
  return 0;
}

Lua 5.1  Copyright (C) 1994-2006 Lua.org, PUC-Rio
require'environ'
printupv = function(f) print(string.format('env: %d, upvalue: %d', f())) end
printupv(env1)
env: 0, upvalue: 0
printupv(env1)
env: 1, upvalue: 1
printupv(env2)
env: 2, upvalue: 0
printupv(env2)
env: 3, upvalue: 1
printupv(env3)
env: 0, upvalue: 0
printupv(env3)
env: 1, upvalue: 1
printupv(env1)
env: 4, upvalue: 2
printupv(env1)
env: 5, upvalue: 3
printupv(env2)
env: 6, upvalue: 2
printupv(env2)
env: 7, upvalue: 3

For more examples of LUA_ENVIRONINDEX, check liolib.c.

Cheers,
Luis.

--
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos

--
Luis Carvalho
Applied Math PhD Student - Brown University
PGP Key: E820854A <carvalho@dam.brown.edu>