/* -- 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)) {
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. */
} 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;
}
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. */
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);
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. */
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);
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)) {
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));
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));
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;
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. */
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 {
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)
{
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; }
}
{
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;
}
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;
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;
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;
}