From fe0838cd1c75e309f9d136d69f9d77e997181d80 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 10 Sep 2007 14:59:32 -0300 Subject: [PATCH] tables and strings respect __len metamethod --- ltm.c | 6 +++--- ltm.h | 4 ++-- lvm.c | 47 +++++++++++++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/ltm.c b/ltm.c index 3b4715dd..5ab2e8b4 100644 --- a/ltm.c +++ b/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; diff --git a/ltm.h b/ltm.h index dcb14fc6..7f1c1e5d 100644 --- a/ltm.h +++ b/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, diff --git a/lvm.c b/lvm.c index 054327a7..6e227053 100644 --- a/lvm.c +++ b/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: {