Browse Source

FFI: Add support for parameterized C types.

Mike Pall 13 years ago
parent
commit
946c7418d5
4 changed files with 57 additions and 10 deletions
  1. 12 9
      src/lib_ffi.c
  2. 43 1
      src/lj_cparse.c
  3. 1 0
      src/lj_cparse.h
  4. 1 0
      src/lj_errmsg.h

+ 12 - 9
src/lib_ffi.c

@@ -35,7 +35,7 @@
 /* -- C type checks ------------------------------------------------------- */
 
 /* Check first argument for a C type and returns its ID. */
-static CTypeID ffi_checkctype(lua_State *L, CTState *cts)
+static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
 {
   TValue *o = L->base;
   if (!(o < L->top)) {
@@ -50,6 +50,7 @@ static CTypeID ffi_checkctype(lua_State *L, CTState *cts)
     cp.cts = cts;
     cp.srcname = strdata(s);
     cp.p = strdata(s);
+    cp.param = param;
     cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
     errcode = lj_cparse(&cp);
     if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
@@ -57,6 +58,7 @@ static CTypeID ffi_checkctype(lua_State *L, CTState *cts)
   } else {
     GCcdata *cd;
     if (!tviscdata(o)) goto err_argtype;
+    if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
     cd = cdataV(o);
     return cd->typeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->typeid;
   }
@@ -442,6 +444,7 @@ LJLIB_CF(ffi_cdef)
   cp.cts = ctype_cts(L);
   cp.srcname = strdata(s);
   cp.p = strdata(s);
+  cp.param = L->base+1;
   cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
   errcode = lj_cparse(&cp);
   if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
@@ -452,7 +455,7 @@ LJLIB_CF(ffi_cdef)
 LJLIB_CF(ffi_new)	LJLIB_REC(.)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   CType *ct = ctype_raw(cts, id);
   CTSize sz;
   CTInfo info = lj_ctype_info(cts, id, &sz);
@@ -492,7 +495,7 @@ LJLIB_CF(ffi_new)	LJLIB_REC(.)
 LJLIB_CF(ffi_cast)	LJLIB_REC(ffi_new)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   CType *d = ctype_raw(cts, id);
   TValue *o = lj_lib_checkany(L, 2);
   L->top = o+1;  /* Make sure this is the last item on the stack. */
@@ -510,7 +513,7 @@ LJLIB_CF(ffi_cast)	LJLIB_REC(ffi_new)
 LJLIB_CF(ffi_typeof)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, L->base+1);
   GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
   *(CTypeID *)cdataptr(cd) = id;
   setcdataV(L, L->top-1, cd);
@@ -521,7 +524,7 @@ LJLIB_CF(ffi_typeof)
 LJLIB_CF(ffi_istype)	LJLIB_REC(ffi_istype)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id1 = ffi_checkctype(L, cts);
+  CTypeID id1 = ffi_checkctype(L, cts, NULL);
   TValue *o = lj_lib_checkany(L, 2);
   int b = 0;
   if (tviscdata(o)) {
@@ -551,7 +554,7 @@ LJLIB_CF(ffi_istype)	LJLIB_REC(ffi_istype)
 LJLIB_CF(ffi_sizeof)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   CTSize sz;
   if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
     sz = cdatavlen(cdataV(L->base));
@@ -573,7 +576,7 @@ LJLIB_CF(ffi_sizeof)
 LJLIB_CF(ffi_alignof)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   CTSize sz = 0;
   CTInfo info = lj_ctype_info(cts, id, &sz);
   setintV(L->top-1, 1 << ctype_align(info));
@@ -583,7 +586,7 @@ LJLIB_CF(ffi_alignof)
 LJLIB_CF(ffi_offsetof)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   GCstr *name = lj_lib_checkstr(L, 2);
   CType *ct = lj_ctype_rawref(cts, id);
   CTSize ofs;
@@ -700,7 +703,7 @@ LJLIB_PUSH(top-8) LJLIB_SET(!)  /* Store reference to miscmap table. */
 LJLIB_CF(ffi_metatype)
 {
   CTState *cts = ctype_cts(L);
-  CTypeID id = ffi_checkctype(L, cts);
+  CTypeID id = ffi_checkctype(L, cts, NULL);
   GCtab *mt = lj_lib_checktab(L, 2);
   GCtab *t = cts->miscmap;
   CType *ct = ctype_get(cts, id);  /* Only allow raw types. */

+ 43 - 1
src/lj_cparse.c

@@ -121,6 +121,7 @@ LJ_NORET static void cp_errmsg(CPState *cp, CPToken tok, ErrMsg em, ...)
     tokstr = NULL;
   } else if (tok == CTOK_IDENT || tok == CTOK_INTEGER || tok == CTOK_STRING ||
 	     tok >= CTOK_FIRSTDECL) {
+    if (cp->sb.n == 0) cp_save(cp, '$');
     cp_save(cp, '\0');
     tokstr = cp->sb.buf;
   } else {
@@ -203,6 +204,38 @@ static CPToken cp_ident(CPState *cp)
   return CTOK_IDENT;
 }
 
+/* Parse parameter. */
+static CPToken cp_param(CPState *cp)
+{
+  CPChar c = cp_get(cp);
+  TValue *o = cp->param;
+  if (lj_char_isident(c) || c == '$')  /* Reserve $xyz for future extensions. */
+    cp_errmsg(cp, c, LJ_ERR_XSYNTAX);
+  if (!o || o >= cp->L->top)
+    cp_err(cp, LJ_ERR_FFI_NUMPARAM);
+  cp->param = o+1;
+  if (tvisstr(o)) {
+    cp->str = strV(o);
+    cp->val.id = lj_ctype_getname(cp->cts, &cp->ct, cp->str, cp->tmask);
+    if (ctype_type(cp->ct->info) == CT_KW)
+      return ctype_cid(cp->ct->info);
+    return CTOK_IDENT;
+  } else if (tvisnumber(o)) {
+    cp->val.i32 = numberVint(o);
+    cp->val.id = CTID_INT32;
+    return CTOK_INTEGER;
+  } else {
+    GCcdata *cd;
+    if (!tviscdata(o)) lj_err_argtype(cp->L, o-cp->L->base+1, "type parameter");
+    cd = cdataV(o);
+    if (cd->typeid == CTID_CTYPEID)
+      cp->val.id = *(CTypeID *)cdataptr(cd);
+    else
+      cp->val.id = cd->typeid;
+    return '$';
+  }
+}
+
 /* Parse string or character constant. */
 static CPToken cp_string(CPState *cp)
 {
@@ -317,6 +350,8 @@ static CPToken cp_next_(CPState *cp)
       return '>';
     case '-':
       cp_get(cp); if (cp->c != '>') return '-'; cp_get(cp); return CTOK_DEREF;
+    case '$':
+      return cp_param(cp);
     case '\0': return CTOK_EOF;
     default: { CPToken c = cp->c; cp_get(cp); return c; }
     }
@@ -403,6 +438,7 @@ static int cp_istypedecl(CPState *cp)
 {
   if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECL) return 1;
   if (cp->tok == CTOK_IDENT && ctype_istypedef(cp->ct->info)) return 1;
+  if (cp->tok == '$') return 1;
   return 0;
 }
 
@@ -1441,7 +1477,7 @@ static CTypeID cp_decl_enum(CPState *cp, CPDecl *sdecl)
 static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl)
 {
   uint32_t cds = 0, sz = 0;
-  CTInfo tdef = 0;
+  CTypeID tdef = 0;
 
   decl->cp = cp;
   decl->mode = cp->mode;
@@ -1471,6 +1507,10 @@ static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl)
       tdef = ctype_cid(cp->ct->info);  /* Get typedef. */
       cp_next(cp);
       break;
+    case '$':
+      tdef = cp->val.id;
+      cp_next(cp);
+      break;
     default:
       if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECLFLAG) {
 	uint32_t cbit;
@@ -1826,6 +1866,8 @@ static TValue *cpcparser(lua_State *L, lua_CFunction dummy, void *ud)
     cp_decl_multi(cp);
   else
     cp_decl_single(cp);
+  if (cp->param && cp->param != cp->L->top)
+    cp_err(cp, LJ_ERR_FFI_NUMPARAM);
   lua_assert(cp->depth == 0);
   return NULL;
 }

+ 1 - 0
src/lj_cparse.h

@@ -48,6 +48,7 @@ typedef struct CPState {
   SBuf sb;		/* String buffer for tokens. */
   lua_State *L;		/* Lua state. */
   CTState *cts;		/* C type state. */
+  TValue *param;	/* C type parameters. */
   const char *srcname;	/* Current source name. */
   BCLine linenumber;	/* Input line counter. */
   int depth;		/* Recursive declaration depth. */

+ 1 - 0
src/lj_errmsg.h

@@ -149,6 +149,7 @@ ERRDEF(FFI_BADSCL,	"bad storage class")
 ERRDEF(FFI_DECLSPEC,	"declaration specifier expected")
 ERRDEF(FFI_BADTAG,	"undeclared or implicit tag " LUA_QS)
 ERRDEF(FFI_REDEF,	"attempt to redefine " LUA_QS)
+ERRDEF(FFI_NUMPARAM,	"wrong number of type parameters")
 ERRDEF(FFI_INITOV,	"too many initializers for " LUA_QS)
 ERRDEF(FFI_BADCONV,	"cannot convert " LUA_QS " to " LUA_QS)
 ERRDEF(FFI_BADLEN,	"attempt to get length of " LUA_QS)