瀏覽代碼

tables and strings respect __len metamethod

Roberto Ierusalimschy 18 年之前
父節點
當前提交
fe0838cd1c
共有 3 個文件被更改,包括 34 次插入23 次删除
  1. 3 3
      ltm.c
  2. 2 2
      ltm.h
  3. 29 18
      lvm.c

+ 3 - 3
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 2.7 2005/12/22 16:19:56 roberto Exp roberto $
+** $Id: ltm.c,v 2.8 2006/01/10 12:50:00 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -30,9 +30,9 @@ const char *const luaT_typenames[] = {
 void luaT_init (lua_State *L) {
   static const char *const luaT_eventname[] = {  /* ORDER TM */
     "__index", "__newindex",
-    "__gc", "__mode", "__eq",
+    "__gc", "__mode", "__len", "__eq",
     "__add", "__sub", "__mul", "__div", "__mod",
-    "__pow", "__unm", "__len", "__lt", "__le",
+    "__pow", "__unm", "__lt", "__le",
     "__concat", "__call"
   };
   int i;

+ 2 - 2
ltm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.h,v 2.5 2005/05/20 15:53:42 roberto Exp roberto $
+** $Id: ltm.h,v 2.6 2005/06/06 13:30:25 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -20,6 +20,7 @@ typedef enum {
   TM_NEWINDEX,
   TM_GC,
   TM_MODE,
+  TM_LEN,
   TM_EQ,  /* last tag method with `fast' access */
   TM_ADD,
   TM_SUB,
@@ -28,7 +29,6 @@ typedef enum {
   TM_MOD,
   TM_POW,
   TM_UNM,
-  TM_LEN,
   TM_LT,
   TM_LE,
   TM_CONCAT,

+ 29 - 18
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.71 2007/03/26 15:56:23 roberto Exp roberto $
+** $Id: lvm.c,v 2.72 2007/06/19 19:48:15 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -310,6 +310,33 @@ void luaV_concat (lua_State *L, int total, int last) {
 }
 
 
+static void objlen (lua_State *L, StkId ra, const TValue *rb) {
+  const TValue *tm;
+  switch (ttype(rb)) {
+    case LUA_TTABLE: {
+      Table *h = hvalue(rb);
+      tm = fasttm(L, h->metatable, TM_LEN);
+      if (tm) break;  /* metamethod? break switch to call it */
+      setnvalue(ra, cast_num(luaH_getn(h)));  /* else primitive len */
+      return;
+    }
+    case LUA_TSTRING: {
+      tm = fasttm(L, G(L)->mt[LUA_TSTRING], TM_LEN);
+      if (tm) break;  /* metamethod? break switch to call it */
+      setnvalue(ra, cast_num(tsvalue(rb)->len));
+      return;
+    }
+    default: {  /* try metamethod */
+      tm = luaT_gettmbyobj(L, rb, TM_LEN);
+      if (ttisnil(tm))  /* no metamethod? */
+        luaG_typeerror(L, rb, "get length of");
+      break;
+    }
+  }
+  callTMres(L, ra, tm, rb, luaO_nilobject);
+}
+
+
 static void Arith (lua_State *L, StkId ra, const TValue *rb,
                    const TValue *rc, TMS op) {
   TValue tempb, tempc;
@@ -509,23 +536,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         continue;
       }
       case OP_LEN: {
-        const TValue *rb = RB(i);
-        switch (ttype(rb)) {
-          case LUA_TTABLE: {
-            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
-            break;
-          }
-          case LUA_TSTRING: {
-            setnvalue(ra, cast_num(tsvalue(rb)->len));
-            break;
-          }
-          default: {  /* try metamethod */
-            Protect(
-              if (!call_binTM(L, rb, rb, ra, TM_LEN))
-                luaG_typeerror(L, rb, "get length of");
-            )
-          }
-        }
+        Protect(objlen(L, ra, RB(i)));
         continue;
       }
       case OP_CONCAT: {