lua

A copy of the Lua development repository
Log | Files | Refs | README

commit f9037ae8c1ccb614e38cb56054927aef6203cfd9
parent 57d842414670769fff8ad045693dcbf1018c59c1
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Thu, 24 Jul 2014 16:33:04 -0300

'ipairs' respects metamethods

Diffstat:
Mlbaselib.c | 46+++++++++++++++++++++++++++++++++++++++++-----
Mltests.h | 3++-
Mluaconf.h | 7++++++-
3 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/lbaselib.c b/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.291 2014/07/16 13:56:59 roberto Exp roberto $ +** $Id: lbaselib.c,v 1.292 2014/07/17 13:53:37 roberto Exp roberto $ ** Basic library ** See Copyright Notice in lua.h */ @@ -244,17 +244,53 @@ static int luaB_pairs (lua_State *L) { } -static int ipairsaux (lua_State *L) { - int i = luaL_checkint(L, 2); +/* +** Traversal function for 'ipairs' for raw tables +*/ +static int ipairsaux_raw (lua_State *L) { + int i = luaL_checkint(L, 2) + 1; luaL_checktype(L, 1, LUA_TTABLE); - i++; /* next value */ lua_pushinteger(L, i); return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2; } +/* +** Traversal function for 'ipairs' for tables with metamethods +*/ +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2) + 1; + if (i > luaL_len(L, 1)) { /* larger than length? */ + lua_pushnil(L); /* end traversal */ + return 1; + } + else { + lua_pushinteger(L, i); + lua_pushinteger(L, i); /* key for indexing table */ + lua_gettable(L, 1); + return 2; + } +} + + +/* +** This function will use either 'ipairsaux' or 'ipairsaux_raw' to +** traverse a table, depending on whether the table has metamethods +** that can affect the traversal. +*/ static int luaB_ipairs (lua_State *L) { - return pairsmeta(L, "__ipairs", 1, ipairsaux); + lua_CFunction iter = + (luaL_getmetafield(L, 1, "__len") || + luaL_getmetafield(L, 1, "__index")) + ? ipairsaux : ipairsaux_raw; +#if defined(LUA_COMPAT_IPAIRS) + return pairsmeta(L, "__ipairs", 1, iter); +#else + lua_pushcfunction(L, iter); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +#endif } diff --git a/ltests.h b/ltests.h @@ -1,5 +1,5 @@ /* -** $Id: ltests.h,v 2.37 2014/07/23 17:16:50 roberto Exp roberto $ +** $Id: ltests.h,v 2.38 2014/07/24 14:00:16 roberto Exp roberto $ ** Internal Header for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ /* test Lua with no compatibility code */ #undef LUA_COMPAT_MATHLIB +#undef LUA_COMPAT_IPAIRS #undef LUA_COMPAT_BITLIB #undef LUA_COMPAT_APIUNSIGNED #undef LUA_COMPAT_FLOATSTRING diff --git a/luaconf.h b/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.210 2014/07/17 13:53:37 roberto Exp roberto $ +** $Id: luaconf.h,v 1.211 2014/07/24 14:00:16 roberto Exp roberto $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -305,6 +305,11 @@ #define LUA_COMPAT_BITLIB /* +@@ LUA_COMPAT_IPAIRS controls the effectivness of the __ipairs metamethod. +*/ +#define LUA_COMPAT_IPAIRS + +/* @@ LUA_COMPAT_APIUNSIGNED controls the presence of macros for ** manipulating unsigned integers (lua_pushunsigned, lua_tounsigned, etc.) */