Browse Source

FFI: Handle __pairs/__ipairs metamethods for cdata objects.

Mike Pall 13 years ago
parent
commit
0648fd47cb
5 changed files with 47 additions and 7 deletions
  1. 10 1
      doc/ext_ffi_api.html
  2. 6 2
      src/lib_base.c
  3. 24 0
      src/lib_ffi.c
  4. 1 0
      src/lj_errmsg.h
  5. 6 4
      src/lj_obj.h

+ 10 - 1
doc/ext_ffi_api.html

@@ -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>

+ 6 - 2
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;

+ 24 - 0
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"

+ 1 - 0
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")

+ 6 - 4
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,