FFI: Handle __pairs/__ipairs metamethods for cdata objects.

This commit is contained in:
Mike Pall 2012-09-03 21:10:10 +02:00
parent 90ec1f90d0
commit 0648fd47cb
5 changed files with 47 additions and 7 deletions

View File

@ -525,7 +525,16 @@ Returns a string representation of the value of 64 bit integers
complex numbers (<tt><b>"</b>re&plusmn;im<b>i"</b></tt>). Otherwise
returns a string representation of the C&nbsp;type of a ctype object
(<tt><b>"ctype&lt;</b>type<b>&gt;"</b></tt>) or a cdata object
(<tt><b>"cdata&lt;</b>type<b>&gt;:&nbsp;</b>address"</tt>).
(<tt><b>"cdata&lt;</b>type<b>&gt;:&nbsp;</b>address"</tt>), unless you
override it with a <tt>__tostring</tt> metamethod (see
<a href="#ffi_metatype"><tt>ffi.metatype()</tt></a>).
</p>
<h3 id="pairs"><tt>iter, obj, start = pairs(cdata)<br>
iter, obj, start = ipairs(cdata)<br></tt></h3>
<p>
Calls the <tt>__pairs</tt> or <tt>__ipairs</tt> metamethod of the
corresponding ctype.
</p>
<h2 id="literals">Extensions to the Lua Parser</h2>

View File

@ -278,12 +278,16 @@ LJLIB_ASM(next)
return FFH_UNREACHABLE;
}
#ifdef LUAJIT_ENABLE_LUA52COMPAT
#if defined(LUAJIT_ENABLE_LUA52COMPAT) || LJ_HASFFI
static int ffh_pairs(lua_State *L, MMS mm)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo = lj_meta_lookup(L, o, mm);
if (!tvisnil(mo)) {
if (
#if !defined(LUAJIT_ENABLE_LUA52COMPAT)
tviscdata(o) &&
#endif
!tvisnil(mo)) {
L->top = o+1; /* Only keep one argument. */
copyTV(L, L->base-1, mo); /* Replace callable. */
return FFH_TAILCALL;

View File

@ -323,6 +323,30 @@ checkgc:
return 1;
}
static int ffi_pairs(lua_State *L, MMS mm)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkcdata(L, 1)->ctypeid;
CType *ct = ctype_raw(cts, id);
cTValue *tv;
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
if (!tv)
lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)),
strdata(mmname_str(G(L), mm)));
return lj_meta_tailcall(L, tv);
}
LJLIB_CF(ffi_meta___pairs)
{
return ffi_pairs(L, MM_pairs);
}
LJLIB_CF(ffi_meta___ipairs)
{
return ffi_pairs(L, MM_ipairs);
}
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
#include "lj_libdef.h"

View File

@ -162,6 +162,7 @@ ERRDEF(FFI_NUMARG, "wrong number of arguments for function call")
ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS)
ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed")
ERRDEF(FFI_BADIDXW, LUA_QS " cannot be indexed with " LUA_QS)
ERRDEF(FFI_BADMM, LUA_QS " has no " LUA_QS " metamethod")
ERRDEF(FFI_WRCONST, "attempt to write to constant location")
ERRDEF(FFI_NODECL, "missing declaration for symbol " LUA_QS)
ERRDEF(FFI_BADCBACK, "bad callback")

View File

@ -447,10 +447,12 @@ enum {
#define MMDEF_FFI(_)
#endif
#ifdef LUAJIT_ENABLE_LUA52COMPAT
#define MMDEF_52(_) _(pairs) _(ipairs)
#if defined(LUAJIT_ENABLE_LUA52COMPAT) || LJ_HASFFI
#define MMDEF_PAIRS(_) _(pairs) _(ipairs)
#else
#define MMDEF_52(_)
#define MMDEF_PAIRS(_)
#define MM_pairs 255
#define MM_ipairs 255
#endif
#define MMDEF(_) \
@ -460,7 +462,7 @@ enum {
/* The following must be in ORDER ARITH. */ \
_(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \
/* The following are used in the standard libraries. */ \
_(metatable) _(tostring) MMDEF_FFI(_) MMDEF_52(_)
_(metatable) _(tostring) MMDEF_FFI(_) MMDEF_PAIRS(_)
typedef enum {
#define MMENUM(name) MM_##name,