From df1dc3f1f54a75174cea7298d5c40bc7b99e60ea Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 1 Dec 2009 14:49:48 -0200 Subject: [PATCH] strings in C scripts may be delimited by quotes + new functionality to set C scripts as C hooks --- ltests.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/ltests.c b/ltests.c index 196c86c3..8410e08e 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.79 2009/11/06 17:08:43 roberto Exp roberto $ +** $Id: ltests.c,v 2.80 2009/11/27 15:39:31 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -810,6 +810,9 @@ static int int2fb_aux (lua_State *L) { ** ======================================================= */ + +static void sethookaux (lua_State *L, int mask, int count, const char *code); + static const char *const delimits = " \t\n,;"; static void skip (const char **pc) { @@ -842,11 +845,21 @@ static int getnum_aux (lua_State *L, const char **pc) { return sig*res; } -static const char *getname_aux (char *buff, const char **pc) { +static const char *getname_aux (lua_State *L, char *buff, const char **pc) { int i = 0; skip(pc); - while (**pc != '\0' && !strchr(delimits, **pc)) - buff[i++] = *(*pc)++; + if (**pc == '"' || **pc == '\'') { /* quoted string? */ + int quote = *(*pc)++; + while (**pc != quote) { + if (**pc == '\0') luaL_error(L, "unfinished string in C script"); + buff[i++] = *(*pc)++; + } + (*pc)++; + } + else { + while (**pc != '\0' && !strchr(delimits, **pc)) + buff[i++] = *(*pc)++; + } buff[i] = '\0'; return buff; } @@ -866,7 +879,7 @@ static int getindex_aux (lua_State *L, const char **pc) { #define EQ(s1) (strcmp(s1, inst) == 0) #define getnum (getnum_aux(L, &pc)) -#define getname (getname_aux(buff, &pc)) +#define getname (getname_aux(L, buff, &pc)) #define getindex (getindex_aux(L, &pc)) @@ -874,8 +887,8 @@ static int testC (lua_State *L); static int Cfunck (lua_State *L); static int runC (lua_State *L, lua_State *L1, const char *pc) { - char buff[30]; - if (pc == NULL) return luaL_error(L, "attempt to runC null code"); + char buff[300]; + if (pc == NULL) return luaL_error(L, "attempt to runC null script"); for (;;) { const char *inst = getname; if EQ("") return 0; @@ -1079,6 +1092,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { int i = getindex; lua_pushinteger(L1, lua_objlen(L1, i)); } + else if EQ("append") { + int t = getindex; + int i = lua_objlen(L1, t); + lua_rawseti(L1, t, i + 1); + } else if EQ("getctx") { static const char *const codes[] = {"OK", "YIELD", "ERRRUN", "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"}; @@ -1105,6 +1123,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { lua_tostring(L, b), lua_tostring(L, c)); } + else if EQ("sethook") { + int mask = getnum; + int count = getnum; + sethookaux(L1, mask, count, getname); + } else if EQ("throw") { #if defined(__cplusplus) static struct X { int x; } x; @@ -1163,25 +1186,62 @@ static int makeCfunc (lua_State *L) { /* ** {====================================================== -** tests for yield inside hooks +** tests for C hooks ** ======================================================= */ -static void yieldf (lua_State *L, lua_Debug *ar) { - UNUSED(ar); - lua_yield(L, 0); +/* +** C hook that runs the C script stored in registry.C_HOOK[L] +*/ +static void Chook (lua_State *L, lua_Debug *ar) { + const char *scpt; + const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; + lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); + lua_pushlightuserdata(L, L); + lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ + scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ + lua_pop(L, 2); /* remove C_HOOK and script */ + lua_pushstring(L, events[ar->event]); /* may be used by script */ + lua_pushinteger(L, ar->currentline); /* may be used by script */ + runC(L, L, scpt); /* run script from C_HOOK[L] */ +} + + +/* +** sets registry.C_HOOK[L] = scpt and sets Chook as a hook +*/ +static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { + if (*scpt == '\0') { /* no script? */ + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + return; + } + lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ + if (!lua_istable(L, -1)) { /* no hook table? */ + lua_pop(L, 1); /* remove previous value */ + lua_newtable(L); /* create new C_HOOK table */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ + } + lua_pushlightuserdata(L, L); + lua_pushstring(L, scpt); + lua_settable(L, -3); /* C_HOOK[L] = script */ + lua_sethook(L, Chook, mask, count); } -static int setyhook (lua_State *L) { + +static int sethook (lua_State *L) { if (lua_isnoneornil(L, 1)) lua_sethook(L, NULL, 0, 0); /* turn off hooks */ else { - const char *smask = luaL_checkstring(L, 1); - int count = luaL_optint(L, 2, 0); + const char *scpt = luaL_checkstring(L, 1); + const char *smask = luaL_checkstring(L, 2); + int count = luaL_optint(L, 3, 0); int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (count > 0) mask |= LUA_MASKCOUNT; - lua_sethook(L, yieldf, mask, count); + sethookaux(L, mask, count, scpt); } return 0; } @@ -1232,7 +1292,7 @@ static const struct luaL_Reg tests_funcs[] = { {"ref", tref}, {"resume", coresume}, {"s2d", s2d}, - {"setyhook", setyhook}, + {"sethook", sethook}, {"stacklevel", stacklevel}, {"testC", testC}, {"makeCfunc", makeCfunc},