lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2011/10/13 Dirk Laurie <dirk.laurie@gmail.com>:
> 2011/10/13 Xavier Wang <weasley.wx@gmail.com>:
>> Hi list :)
>>
>> I had notice a incompatible with Lua5.1 and Lua5.2-beta, that is in
>> Lua 5.2 beta, the __len meta-method has two operand! though they are
>> the same one (the userdata I used # operator),
>
> The manual says:
>> "len": the # operation.
>>     function len_event (op)
>
> Why do you say the __len metamethod has two operands?
>
> D.
>
>

Because I have a project that I support both Lua5.1 and Lua5.2, and
the test case fault when I compile my module to 5.2, it seems that
When you write #b, Lua call the meta-method of userdata b like:
mt.__len(b, b). I print the lua_gettop(L) and it return 2, and the
first and second arguments are the same (b), finally I'm looking for
the source of Lua 5.2, and found these lines (in lvm.c, line 317):

void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
  const TValue *tm;
  switch (ttypenv(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: {
      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;
    }
  }
  callTM(L, tm, rb, rb, ra, 1);
}

and this is the callTM function (lvm.c, line 84):

static void callTM (lua_State *L, const TValue *f, const TValue *p1,
                    const TValue *p2, TValue *p3, int hasres) {
  ptrdiff_t result = savestack(L, p3);
  setobj2s(L, L->top++, f);  /* push function */
  setobj2s(L, L->top++, p1);  /* 1st argument */
  setobj2s(L, L->top++, p2);  /* 2nd argument */
  if (!hasres)  /* no result? 'p3' is third argument */
    setobj2s(L, L->top++, p3);  /* 3rd argument */
  luaD_checkstack(L, 0);
  /* metamethod may yield only when called from Lua code */
  luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
  if (hasres) {  /* if has result, move it to its place */
    p3 = restorestack(L, result);
    setobjs2s(L, p3, --L->top);
  }
}


It says, *all* meta-method's parameters plus return values is 3.