Kaynağa Gözat

'ipairs' respects metamethods

Roberto Ierusalimschy 11 yıl önce
ebeveyn
işleme
f9037ae8c1
3 değiştirilmiş dosya ile 49 ekleme ve 7 silme
  1. 41 5
      lbaselib.c
  2. 2 1
      ltests.h
  3. 6 1
      luaconf.h

+ 41 - 5
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
 }
 
 

+ 2 - 1
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

+ 6 - 1
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
 */
@@ -304,6 +304,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.)