From 946c7418d59dd201386ee66686075595754cd86d Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 14 Jun 2012 19:54:07 +0200 Subject: FFI: Add support for parameterized C types. --- src/lib_ffi.c | 21 ++++++++++++--------- src/lj_cparse.c | 44 +++++++++++++++++++++++++++++++++++++++++++- src/lj_cparse.h | 1 + src/lj_errmsg.h | 1 + 4 files changed, 57 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/lib_ffi.c b/src/lib_ffi.c index 2a674b88..f4097041 100644 --- a/src/lib_ffi.c +++ b/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. */ diff --git a/src/lj_cparse.c b/src/lj_cparse.c index ff5abc70..0f8c2857 100644 --- a/src/lj_cparse.c +++ b/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; } diff --git a/src/lj_cparse.h b/src/lj_cparse.h index eaa1bdb5..29188c69 100644 --- a/src/lj_cparse.h +++ b/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. */ diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index 5ba619bf..2d677cca 100644 --- a/src/lj_errmsg.h +++ b/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) -- cgit v1.2.3-55-g6feb