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:
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.)
*/