From 0648fd47cb5560cf1a44a211a75997863e8470dd Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Mon, 3 Sep 2012 21:10:10 +0200 Subject: [PATCH] FFI: Handle __pairs/__ipairs metamethods for cdata objects. --- doc/ext_ffi_api.html | 11 ++++++++++- src/lib_base.c | 8 ++++++-- src/lib_ffi.c | 24 ++++++++++++++++++++++++ src/lj_errmsg.h | 1 + src/lj_obj.h | 10 ++++++---- 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html index 16066612..503c6e4a 100644 --- a/doc/ext_ffi_api.html +++ b/doc/ext_ffi_api.html @@ -525,7 +525,16 @@ Returns a string representation of the value of 64 bit integers complex numbers ("re±imi"). Otherwise returns a string representation of the C type of a ctype object ("ctype<type>") or a cdata object -("cdata<type>: address"). +("cdata<type>: address"), unless you +override it with a __tostring metamethod (see +ffi.metatype()). +

+ +

iter, obj, start = pairs(cdata)
+iter, obj, start = ipairs(cdata)

+

+Calls the __pairs or __ipairs metamethod of the +corresponding ctype.

Extensions to the Lua Parser

diff --git a/src/lib_base.c b/src/lib_base.c index 9702c5b4..824fc0e7 100644 --- a/src/lib_base.c +++ b/src/lib_base.c @@ -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; diff --git a/src/lib_ffi.c b/src/lib_ffi.c index 24a6625c..69bebefc 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -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" diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index 5b10dea8..dd3eefa8 100644 --- a/src/lj_errmsg.h +++ b/src/lj_errmsg.h @@ -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") diff --git a/src/lj_obj.h b/src/lj_obj.h index 7890e54b..67fb5ed9 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -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,