new functions `dofile' and `pairs'; correct way to check proxies

This commit is contained in:
Roberto Ierusalimschy 2002-06-25 16:19:33 -03:00
parent 78c507b7b8
commit 25dc9b7faf
1 changed files with 50 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.83 2002/06/20 20:41:46 roberto Exp roberto $ ** $Id: lbaselib.c,v 1.84 2002/06/24 17:23:16 roberto Exp roberto $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -34,7 +34,7 @@ static int luaB_print (lua_State *L) {
const char *s; const char *s;
lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */ lua_pushvalue(L, i); /* value to print */
lua_upcall(L, 1, 1); lua_call(L, 1, 1);
s = lua_tostring(L, -1); /* get result */ s = lua_tostring(L, -1); /* get result */
if (s == NULL) if (s == NULL)
return luaL_error(L, "`tostring' must return a string to `print'"); return luaL_error(L, "`tostring' must return a string to `print'");
@ -83,8 +83,10 @@ static int luaB_error (lua_State *L) {
static int luaB_getmetatable (lua_State *L) { static int luaB_getmetatable (lua_State *L) {
luaL_check_any(L, 1); luaL_check_any(L, 1);
if (!lua_getmetatable(L, 1)) if (!lua_getmetatable(L, 1)) {
return 0; /* no metatable */ lua_pushnil(L);
return 1; /* no metatable */
}
else { else {
lua_pushliteral(L, "__metatable"); lua_pushliteral(L, "__metatable");
lua_rawget(L, -2); lua_rawget(L, -2);
@ -182,11 +184,20 @@ static int luaB_next (lua_State *L) {
} }
static int luaB_nexti (lua_State *L) { static int luaB_pairs (lua_State *L) {
luaL_check_type(L, 1, LUA_TTABLE);
lua_getglobal(L, "next"); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
return 3;
}
static int luaB_ipairs (lua_State *L) {
lua_Number i = lua_tonumber(L, 2); lua_Number i = lua_tonumber(L, 2);
luaL_check_type(L, 1, LUA_TTABLE); luaL_check_type(L, 1, LUA_TTABLE);
if (i == 0 && lua_isnull(L, 2)) { /* `for' start? */ if (i == 0 && lua_isnull(L, 2)) { /* `for' start? */
lua_getglobal(L, "nexti"); /* return generator, */ lua_getglobal(L, "ipairs"); /* return generator, */
lua_pushvalue(L, 1); /* state, */ lua_pushvalue(L, 1); /* state, */
lua_pushnumber(L, 0); /* and initial value */ lua_pushnumber(L, 0); /* and initial value */
return 3; return 3;
@ -225,6 +236,15 @@ static int luaB_loadfile (lua_State *L) {
} }
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_opt_string(L, 1, NULL);
int status = luaL_loadfile(L, fname);
if (status != 0) lua_error(L);
lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - 1;
}
static int luaB_assert (lua_State *L) { static int luaB_assert (lua_State *L) {
luaL_check_any(L, 1); luaL_check_any(L, 1);
if (!lua_toboolean(L, 1)) if (!lua_toboolean(L, 1))
@ -294,21 +314,27 @@ static int luaB_tostring (lua_State *L) {
static int luaB_newproxy (lua_State *L) { static int luaB_newproxy (lua_State *L) {
void *u; static const char dummy = '\0';
lua_pushnil(L); /* default argument (if there is nothing at stack[1]) */ lua_settop(L, 1);
u = lua_newuserdata(L, sizeof(lua_CFunction)); /* create proxy */ luaL_weakregistry(L); /* get weak registry */
*(lua_CFunction *)u = luaB_newproxy; /* mark it as a proxy */ lua_newuserdata(L, 0); /* create proxy */
if (lua_toboolean(L, 1) == 0) if (lua_toboolean(L, 1) == 0)
return 1; /* no metatable */ return 1; /* no metatable */
else if ((u = lua_touserdata(L, 1)) != NULL) { else if (lua_isboolean(L, 1)) {
luaL_arg_check(L, *(lua_CFunction *)u == luaB_newproxy, 1, "invalid proxy"); lua_newtable(L); /* create a new metatable `m' ... */
lua_getmetatable(L, 1); /* reuse metatable */ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
lua_pushudataval(L, (void *)&dummy);
lua_rawset(L, 2); /* weakregistry[m] = &dummy */
} }
else { else {
luaL_check_type(L, 1, LUA_TBOOLEAN); if (lua_getmetatable(L, 1)) /* check whether registry[m] == &dummy */
lua_newtable(L); /* create a new metatable */ lua_rawget(L, 2);
luaL_arg_check(L, (char *)lua_touserdata(L, -1) == &dummy, 1,
"boolean/proxy expected");
lua_getmetatable(L, 1); /* metatable is valid */
} }
lua_setmetatable(L, -2); lua_setmetatable(L, 3);
lua_pushvalue(L, 3);
return 1; return 1;
} }
@ -380,7 +406,7 @@ static int luaB_require (lua_State *L) {
if (!lua_istable(L, 2)) return luaL_error(L, REQTAB " is not a table"); if (!lua_istable(L, 2)) return luaL_error(L, REQTAB " is not a table");
path = getpath(L); path = getpath(L);
lua_pushvalue(L, 1); /* check package's name in book-keeping table */ lua_pushvalue(L, 1); /* check package's name in book-keeping table */
lua_gettable(L, 2); lua_rawget(L, 2);
if (!lua_isnil(L, -1)) /* is it there? */ if (!lua_isnil(L, -1)) /* is it there? */
return 0; /* package is already loaded */ return 0; /* package is already loaded */
else { /* must load it */ else { /* must load it */
@ -393,10 +419,10 @@ static int luaB_require (lua_State *L) {
} }
switch (status) { switch (status) {
case 0: { case 0: {
lua_upcall(L, 0, 0); /* run loaded module */ lua_call(L, 0, 0); /* run loaded module */
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
lua_settable(L, 2); /* mark it as loaded */ lua_rawset(L, 2); /* mark it as loaded */
return 0; return 0;
} }
case LUA_ERRFILE: { /* file not found */ case LUA_ERRFILE: { /* file not found */
@ -419,7 +445,8 @@ static const luaL_reg base_funcs[] = {
{"getglobals", luaB_getglobals}, {"getglobals", luaB_getglobals},
{"setglobals", luaB_setglobals}, {"setglobals", luaB_setglobals},
{"next", luaB_next}, {"next", luaB_next},
{"nexti", luaB_nexti}, {"ipairs", luaB_ipairs},
{"pairs", luaB_pairs},
{"print", luaB_print}, {"print", luaB_print},
{"tonumber", luaB_tonumber}, {"tonumber", luaB_tonumber},
{"tostring", luaB_tostring}, {"tostring", luaB_tostring},
@ -434,6 +461,7 @@ static const luaL_reg base_funcs[] = {
{"collectgarbage", luaB_collectgarbage}, {"collectgarbage", luaB_collectgarbage},
{"gcinfo", luaB_gcinfo}, {"gcinfo", luaB_gcinfo},
{"loadfile", luaB_loadfile}, {"loadfile", luaB_loadfile},
{"dofile", luaB_dofile},
{"loadstring", luaB_loadstring}, {"loadstring", luaB_loadstring},
{"require", luaB_require}, {"require", luaB_require},
{NULL, NULL} {NULL, NULL}
@ -531,8 +559,8 @@ static void base_open (lua_State *L) {
luaL_openlib(L, base_funcs, 0); /* open lib into global table */ luaL_openlib(L, base_funcs, 0); /* open lib into global table */
lua_pushliteral(L, "_VERSION"); lua_pushliteral(L, "_VERSION");
lua_pushliteral(L, LUA_VERSION); lua_pushliteral(L, LUA_VERSION);
lua_settable(L, -3); /* set global _VERSION */ lua_rawset(L, -3); /* set global _VERSION */
lua_settable(L, -1); /* set global _G */ lua_rawset(L, -1); /* set global _G */
} }